Tud*_*dor 7 postgresql postgresql-9.0
我正在使用 Postgresql 9.0。我在表中有以下字段:id, name
.
id name
1 John
1 Mary
1 Mary
1 Mary
1 John
1 Mary
3 Paul
3 Paul
3 George
. .
. .
Run Code Online (Sandbox Code Playgroud)
对于每个id
,我想选择出现次数最多的名称。我怎样才能做到这一点?
我尝试使用以下查询,但它不起作用:
select id, max(name)
from table
group by id;
Run Code Online (Sandbox Code Playgroud)
这不是小事。首先,您需要按 id 和 name 分组并计算行数:
SELECT COUNT(*)
...
GROUP BY id, name
Run Code Online (Sandbox Code Playgroud)
然后为每个 id 选择最大计数。实现此目的的一种方法是通过窗口函数。该RANK()
函数:
RANK() OVER (PARTITION BY id ORDER BY COUNT(*) DESC)
Run Code Online (Sandbox Code Playgroud)
为结果的每一行分配一个数字(在分组完成后),将它们(行)排列在具有相同id
和排序依据的COUNT(*) DESC
分区中,因此对于每个 (partition of) id
,具有最大计数的行是分配的等级为 1。因此,我们需要将上述内容放在派生表中,并使用WHERE
条件仅保留这些行:
WHERE rnk = 1
Run Code Online (Sandbox Code Playgroud)
最后的查询是这样的:
SELECT
id, name, cnt
FROM
( SELECT id, name, COUNT(*) AS cnt,
RANK() OVER (PARTITION BY id ORDER BY COUNT(*) DESC) AS rnk
FROM tableX
GROUP BY id, name
) AS tg
WHERE
rnk = 1 ;
Run Code Online (Sandbox Code Playgroud)
在SQL-Fiddle测试
请注意,如果您首先有联系(两个或更多名称具有相同的最大计数),则所有这些都将被返回。如果您希望最终结果中每个 id 严格为一行,则必须使用 theROW_NUMBER()
而不是 theRANK()
并可能更改ORDER BY
子句以明确选择如何解决关系:
ROW_NUMBER() OVER (PARTITION BY id ORDER BY COUNT(*) DESC, name ASC) AS rnk
Run Code Online (Sandbox Code Playgroud)