PostgreSQL 9.6:按组优先选取foo=A行的实现方法
解决PostgreSQL按组优先选取指定行的问题
先明确你的原始数据(假设表名为your_table):
group | foo | value ------+-----+------ 1 | A | a 1 | B | b 1 | C | c 2 | B | b2 2 | A | a2 3 | B | b3 3 | C | c3
需求很清晰:每组返回一行,优先选取组内foo = 'A'的行,如果没有就任选一行。下面是两种高效的实现方式:
方法1:使用窗口函数ROW_NUMBER()
这是通用的SQL方案,其他支持窗口函数的数据库也能复用:
SELECT "group", foo, value FROM ( SELECT "group", foo, value, -- 给每组的行分配优先级:A排1,其他排2 ROW_NUMBER() OVER ( PARTITION BY "group" ORDER BY CASE WHEN foo = 'A' THEN 1 ELSE 2 END ) AS row_num FROM your_table ) ranked_rows WHERE row_num = 1;
原理说明:
PARTITION BY "group":把数据按group字段拆分成独立的组ORDER BY CASE ...:给foo='A'的行设置最高优先级,确保它在组内排第一- 外层筛选
row_num=1,就能拿到每组的目标行
方法2:使用PostgreSQL特有的DISTINCT ON
这个语法更简洁,是PostgreSQL的专属特性,写起来更清爽:
SELECT DISTINCT ON ("group") "group", foo, value FROM your_table -- 先按组排序,再按优先级排序,确保A行在组内最前面 ORDER BY "group", CASE WHEN foo = 'A' THEN 1 ELSE 2 END;
原理说明:
DISTINCT ON ("group")会返回每组的第一行ORDER BY子句先按group分组排序,再按优先级排序,这样foo='A'的行就会成为每组的第一行被选中;如果组内没有A,就取排序后的第一行(也就是原数据里的第一个匹配行)
最终输出结果
两种方法都会得到你想要的结果:
group | foo | value ------+-----+------ 1 | A | a 2 | A | a2 3 | B | b3
⚠️ 注意:group是PostgreSQL的关键字,所以在SQL里要用双引号"group"括起来,避免语法错误。如果你的实际字段名不是这个,记得替换成自己的字段名。
内容的提问来源于stack exchange,提问作者vektor
相关产品推荐
相关产品推荐

