PostgreSQL 13中如何对相同值的行进行分组且不破坏ORDER BY后的排序结果?
解决PostgreSQL中分组相同price行且保留原排序的问题
嘿,我看了你在PostgreSQL 13里遇到的分组问题,当前的查询用了grouping sets导致每个id对应两行数据,这显然不是你想要的结果。先拆解下你当前查询的问题:你用的grouping sets((tempId,price),(tempId,pemId,title,description))会生成两种分组行——一种是仅按tempId和price聚合的空字段汇总行,另一种是保留所有原字段的明细行,所以才会出现每个tempId重复的情况。
结合你的需求(对相同price的行进行分组,同时确保排序结果不被打乱),我给你两种常见场景的解决方案:
场景1:保留原id排序,给相同price的行标记分组
如果你希望结果完全按照原表的id顺序排列,同时给相同price的行加上分组标识,这里分两种情况:
全局分组(所有同price的行归为同一组)
这个方案会把所有price相同的行分配同一个组号,组号按该price第一次出现的id顺序生成,同时整体结果保持原id排序:
SELECT id AS tempId, id AS pemId, title, description, price, DENSE_RANK() OVER (ORDER BY first_occurrence) AS price_group FROM ( SELECT *, MIN(id) OVER (PARTITION BY price) AS first_occurrence FROM products ) AS sub ORDER BY id;
连续分组(仅相邻同price的行归为一组)
如果你只想把连续出现的相同price行归为一组(比如测试数据里id2、3是一组,id5、6是另一组),可以用LAG()函数判断当前行和前一行的price是否一致:
SELECT id AS tempId, id AS pemId, title, description, price, SUM(price_change) OVER (ORDER BY id) AS price_group FROM ( SELECT *, CASE WHEN LAG(price) OVER (ORDER BY id) = price THEN 0 ELSE 1 END AS price_change FROM products ) AS sub ORDER BY id;
场景2:分组折叠展示(汇总行+明细行,保留原排序)
如果你想要实现类似“分组标题+明细”的展示效果——每个price第一次出现时显示一行汇总信息,后面跟该price的所有明细行,同时整体保持原id的排序顺序,可以用UNION ALL结合窗口函数实现:
-- 先获取每个price的首次出现汇总行 SELECT id AS tempId, NULL AS pemId, CONCAT('Price Group: ', price) AS title, 'Group summary' AS description, price FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY price ORDER BY id) AS rn FROM products ) AS sub WHERE rn = 1 UNION ALL -- 再获取所有明细行 SELECT id AS tempId, id AS pemId, title, description, price FROM products -- 排序确保汇总行在对应明细行之前,同时整体按原id顺序 ORDER BY tempId, CASE WHEN pemId IS NULL THEN 0 ELSE 1 END;
这个查询的结果会是:
| tempId | pemId | title | description | price |
|---|---|---|---|---|
| 1 | Price Group: 2222 | Group summary | 2222 | |
| 1 | 1 | test | test | 2222 |
| 2 | Price Group: 1111 | Group summary | 1111 | |
| 2 | 2 | test | test2 | 1111 |
| 3 | 3 | test3 | test3 | 1111 |
| 4 | Price Group: 555 | Group summary | 555 | |
| 4 | 4 | test3.2 | test3.2 | 555 |
| 5 | 5 | test3.3 | test3.3 | 1111 |
| 6 | 6 | test4 | test4 desc | 1111 |
这样既实现了相同price的分组展示,又完全保留了原id的排序顺序,不会打乱你想要的排序效果。
内容的提问来源于stack exchange,提问作者Muhammad Usman
相关产品推荐
相关产品推荐

