按每组中的最高值对整组结果进行排序

时间:2013-04-05 14:59:50

标签: sql postgresql greatest-n-per-group window-functions

例如,假设我在PostgreSQL中有一个表(高于9.0),填充了数据:

row_id    percent    isrc
1         100        123iee43
2         100        1234wr32
3         98         123iee43
4         99         1234wr32
5         95         12313be3
6         99         12313be3
7         96         12313be3

我希望我的结果包含按列isrc分组的所有上述行,然后是按percent排序的整个组。所以这就是结果应该是这样的:

row_id    percent    isrc
1         100        123iee43
3         98         123iee43
2         100        1234wr32
4         99         1234wr32
6         99         12313be3
7         96         12313be3
5         95         12313be3

如果我想升序,这就是我所期望的(我只想按一个组中的第一行排序,单个组中的其他行无关紧要):

row_id    percent    isrc
6         99         12313be3
7         96         12313be3
5         95         12313be3
1         100        123iee43
3         98         123iee43
2         100        1234wr32
4         99         1234wr32

我想我必须以某种方式使用窗口函数,但如果存在,则无法找到正确的解决方案。此外,如果解决方案尽可能优雅,那将是非常好的。 :)

2 个答案:

答案 0 :(得分:2)

窗口功能

SELECT row_id, percent, isrc
FROM   tbl
ORDER  BY max(percent) OVER(PARTITION BY isrc) DESC, isrc, percent DESC;

聚合函数max()可用作窗函数。我不在窗口子句中使用ORDER BY,因为per documentation

  

当聚合函数用作窗口函数时,它会聚合   在当前行的窗口框架内的行上。使用的聚合   使用ORDER BY并且默认窗口框架定义生成一个   “运行总和”类型的行为,可能是也可能不是想要的。   要获得整个分区的聚合,请省略ORDER BY或使用   ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING。其他框架   规范可用于获得其他效果。

窗口函数不能在WHEREHAVING子句中使用,因为在窗口函数之前应用。但是可以使用最后应用的ORDER BY子句中的一个(即使在DISTINCT之后,但在LIMIT之前)。

窗口函数可能很昂贵,但是这个函数简化了查询,甚至可能比其他选择更快 它肯定是最优雅

聚合函数

JOIN。可能会或可能不会更快。

SELECT row_id, percent, isrc
FROM   tbl
JOIN  (SELECT isrc, max(percent) AS max_pct FROM tbl GROUP BY 1) x USING (isrc)
ORDER  BY x.max_pct DESC, isrc, percent DESC;

DISTINCT ON

与使用聚合函数非常相似。

SELECT t.*
FROM   tbl t
JOIN  (
    SELECT DISTINCT ON (isrc) isrc, percent
    FROM   tbl
    ORDER  BY isrc, percent DESC
    ) s USING (isrc)
ORDER BY s.percent DESC, s.isrc, t.percent DESC

需要一个窗口功能。

SQL Fiddle demonstrating all of the above.

答案 1 :(得分:0)

SQL Fiddle

select t.*
from
    t
    inner join (
        select distinct on (isrc) isrc,
            row_number() over(order by percent desc) rn
        from t
        order by isrc, percent desc
    ) s on t.isrc = s.isrc
order by s.rn, t.percent desc