postgres select TOP X in group 查询每个组的前几名

参考:

https://stackoverflow.com/questions/27415706/postgresql-select-top-three-in-each-group

http://charlesnagy.info/it/postgresql/group-by-limit-per-group-in-postgresql

但实在看不懂这里面LATERAL的用法,而且语法和pg11似乎也有了区别。

这个里面的LATERAL用法倒是看懂了,把LATERAL当成foreach来用:

https://www.oschina.net/translate/postgresqls-powerful-new-join-type-lateral?cmp

简单说,用LATERAL JOIN2个子查询:

1 GROUP BY 得到聚合后的分组

2 再用这个数量缩水的 用WHERE inner.grp = outer.grp 去过滤没缩水前的全部数据。排序得到查询结果

最终外面再包1层select

——但如果inner是个view 等于里面要扫描N次 N等于1的group数量。

我的分组有点多,几百个,实测结果:要5秒钟,实在不能忍,性能太差了

最后,还是用https://stackoverflow.com/questions/27415706/postgresql-select-top-three-in-each-group

里面最直接的窗口函数法,1次FROM就搞定,400ms,就算凑合了

SELECT *
FROM(
    SELECT *
            ,ROW_NUMBER() OVER (PARTITION BY grp 
                                    ORDER BY value DESC) AS order_in_grp 
    FROM table1
    ) AS A
WHERE order_in_grp < 2

子查询里用窗口函数得到每个分组内的序号order_in_grp:按grp字段分组,组内按value降序的序号 

外层只是用WHERE过滤出每个组内前1名。

对我这种新手来说,还是这样简单、直接、标准语法的方式更适合我。怎么用LATERAL才能效率高,暂时无暇顾及了。

起码符合The Zen of Python的前几条

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.

 

心得

不是看见分组就一定要GROUP BY, 窗口函数这样反而更灵活——不聚合,而是,在子查询里给出组内排名order_in_grp字段,然后在外面做1次WHERE把每个分组的前N名过滤出来。 

posted @ 2019-05-13 19:46  永远的幻想  阅读(3013)  评论(0编辑  收藏  举报