【问题标题】:Only return top n results for each group in GROUPING SETS query仅返回 GROUPING SETS 查询中每个组的前 n 个结果
【发布时间】:2017-03-01 03:09:06
【问题描述】:

我有一个相当复杂的查询,使用 GROUPING SETS 执行一些聚合,它大致如下所示:

SELECT 
    column1,
    [... more columns here]
    count(*)
FROM table_a 
GROUP BY GROUPING SETS (
    column1,
    [... more columns here]
)
ORDER BY count DESC

这通常非常有效,只要每个组的结果数量相当少。但是我在这个查询中有一些列可以有大量不同的值,这会导致这个查询返回大量的行。

我实际上只对分组集中每个组的最佳结果感兴趣。但是似乎没有明显的方法来限制使用分组集的查询中每组的结果数,LIMIT 在这种情况下不起作用。

我使用的是 PostgreSQL 9.6,所以在这里我可以使用的新功能不受限制。

所以我的查询是这样的:

| column1 | column2 | count |
|---------|---------|-------|
| DE      |         | 32455 |
| US      |         | 3445  |
| FR      |         | 556   |
| GB      |         | 456   |
| RU      |         | 76    |
|         | 12      | 10234 |
|         | 64      | 9805  |
|         | 2       | 6043  |
|         | 98      | 2356  |
|         | 65      | 1023  |
|         | 34      | 501   |

我真正想要的是只返回前 3 个结果的东西:

| column1 | column2 | count |
|---------|---------|-------|
| DE      |         | 32455 |
| US      |         | 3445  |
| FR      |         | 556   |
|         | 12      | 10234 |
|         | 64      | 9805  |
|         | 2       | 6043  |

【问题讨论】:

  • SELECT 子句中的“分组”是什么?这是 postgres 的正确语法吗?
  • 另外grouping sets 已经给出了不同的行,那么当您说“每个组的最佳结果”时,您的意思是什么?请向我们展示样本数据和异常结果。
  • @OtoShavadze 是 Postgres 特有的函数,用于对集合进行分组以确定行属于哪个集合,这个最小示例实际上不需要它,所以我只是将其删除以避免混淆。我还添加了示例输出。
  • 尝试在外部查询中使用rownum,并为不同的组合并所有

标签: sql postgresql


【解决方案1】:

使用row_numbergrouping

select a, b, total
from (
    select 
        a, b, total, 
        row_number() over(
            partition by g 
            order by total desc
        ) as rn
    from (
        select a, b, count(*) as total, grouping ((a),(b)) as g
        from t
        group by grouping sets ((a),(b))
    ) s
) s
where rn <= 3

【讨论】:

    【解决方案2】:

    类似这样的:

    WITH T(column1 , column2, cnt) AS
    (
    SELECT 'kla', 'k', 10
    UNION ALL
    SELECT 'kle', 'm', 30
    UNION ALL
    SELECT 'foo', 'k', 10
    UNION ALL
    SELECT 'bar', 'm', 30
    UNION ALL
    SELECT 'bar', 'k', 20
    UNION ALL
    SELECT 'foo', 'm', 15
    UNION ALL
    SELECT 'foo', 'p', 10
    ),
    tt AS (select  column1, column2, COUNT(*) AS cnt from t GROUP BY GROUPING SETS( (column1), (column2))  )
    
    (SELECT column1, NULL as column2, cnt FROM tt WHERE column1 IS NOT NULL ORDER BY cnt desc LIMIT 3)
    UNION ALL
    (SELECT NULL as column1, column2, cnt FROM tt WHERE column2 IS NOT NULL ORDER BY cnt desc LIMIT 3)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-30
      • 1970-01-01
      • 2011-09-17
      • 2018-05-16
      • 2014-01-05
      • 2017-10-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多