【问题标题】:获取每列具有最大计数的行 - 同时按两列分组
【发布时间】:2022-01-19 09:14:00
【问题描述】:

我正在尝试获取字段的最大计数。 这就是我得到的,也是我试图做的。

| col1 | col2 |
|  A   |  B   |
|  A   |  B   |
|  A   |  D   |
|  A   |  D   |
|  A   |  D   |
|  C   |  F   |
|  C   |  G   |
|  C   |  F   |

我正在尝试获取col2 的最大出现次数,按col1 分组。

通过这个查询,我得到了按col1col2 分组的事件。

SELECT col1, col2, count(*) as conta 
FROM tab 
WHERE 
GROUP by col1, col2 
ORDER BY col1, col2

我得到:

| col1 | col2 | conta |
|  A   |  B   |   2   |
|  A   |  D   |   3   |
|  C   |  F   |   2   |
|  C   |  G   |   1   |

然后我使用此查询来获取最大计数:

SELECT max(conta) as conta2, col1 
FROM (
    SELECT col1, col2, count(*) as conta 
    FROM tab 
    WHERE 
    GROUP BY col1, col2 
    ORDER BY col1, col2
) AS derivedTable 
GROUP BY col1

我得到:

| col1 | conta |
|  A   |   3   |
|  C   |   2   |

我缺少的是col2 的值。我想要这样的东西:

| col1 | col2 | conta |
|  A   |  D   |   3   |
|  C   |  F   |   2   |

问题是,如果我尝试选择 col2 字段,我会收到一条错误消息,我必须在 group by 或聚合函数中使用此字段,但在 group by 中使用它不是正确的方法.

【问题讨论】:

  • PostGreSQL 是否有具体说明为什么您的第二个查询不起作用?我尝试了完全相同的一个(缺少 col2,中间没有 WHERE,我在 MySQL 上没有收到任何错误消息。
  • 使用 MySQL 可以获得不在 group by 中的字段,即使 select 中有另一个字段的聚合。在 PostgreSQL 中这是不可能的,如果您在 select 中有聚合和其他字段,则此字段必须在聚合本身或 group by 中。

标签: sql postgresql count aggregate greatest-n-per-group


【解决方案1】:

更简单、更快(并且正确):

SELECT DISTINCT ON (col1)
       col1, col2, count(*) AS conta
FROM   tab 
GROUP  BY col1, col2 
ORDER  BY col1, conta DESC;

dbfiddle here(基于 a_horse 的小提琴)

DISTINCT ON 在聚合之后应用,因此我们不需要子查询或 CTE。考虑SELECT 查询中的事件顺序:

【讨论】:

  • 哇,非常感谢!它工作得很好而且非常简单:)
【解决方案2】:

您可以将 GROUP BY 与窗口函数结合起来 - 分组后进行评估:

with cte as (
  SELECT col1, col2, 
         count(*) as conta,
         dense_rank() over (partition by col1 order by count(*) desc) as rnk
  FROM tab 
  WHERE ...
  GROUP by col1, col2 
) 
select col1, col2, conta
from cte
where rnk = 1
order by col1, col2;

这将两次返回具有相同最高最大计数的 col1,col2 的组合。如果您不想这样,请使用row_number() 而不是dense_rank()

Online example

【讨论】:

  • 非常感谢!这完美! :)
【解决方案3】:

可能不是最优雅的解决方案,但使用通用表表达式可能会有所帮助。

with cte as (
select col1, col2, count(*) as total
from dtable 
group by col1, col2
)
select  col1, col2, total 
from cte c
where total = (select max(total) 
           from cte cc
           where cc.col1 = c.col1)
order by col1 asc 

返回

col1|col2|total|
----+----+-----+
 A  | D  |    3|
 C  | F  |    2|

from the docs

【讨论】:

  • 谢谢!有用!我要解决的只是一件事。现在我遇到一种情况,col1 和 col2 的总数相等,因此两行都被选中。我怎样才能只保留第一个或最后一个?
【解决方案4】:

我误解了这个问题。这是您的解决方案:

;with tablex as
    (Select col1, col2, Count(col2) as Count From Your_Table Group by col1, col2),
aaaa as
    (Select ROW_NUMBER() over (partition by col1 order by Count desc) as row, * From tablex)

Select * From aaaa Where row = 1

【讨论】:

  • 这是我尝试的第一个查询,但我只得到了出现次数。我需要出现次数的最大值以及字段 col1 和 col2。
【解决方案5】:

使用窗口函数:

select distinct on (col1) col1, col2, cnt
from 
(
 select col1, col2, count(*) over (partition by col1, col2) cnt 
 from the_table
) t
order by col1, cnt desc;
col1 col2 cnt
A D 3
C F 2

此解决方案不能解决有关系的案例。

【讨论】:

  • 但这不会返回C,F,2
  • @a_horse_with_no_name 不,只是“获取字段的最大计数”。我不确定 OP 需要什么,因为他还提到“我怎样才能只保留第一个或最后一个”,即 C, G, 1
  • 问题包含“想要这样的东西”,其中包括 C,F,2 - 所以对于 col1、col2 的每个组合,计数最高的那个
  • @a_horse_with_no_name 谢谢,是的,我忽略了这一点。答案已更正。
猜你喜欢
  • 1970-01-01
  • 2019-08-09
  • 1970-01-01
  • 2019-06-28
  • 2021-12-04
  • 2021-02-01
  • 1970-01-01
  • 2012-02-14
  • 1970-01-01
相关资源
最近更新 更多