如何在PostgreSQL中仅按单个字段执行GROUP BY操作?
PostgreSQL 实现单字段GROUP BY的解决方案
上述SQL在MySQL能运行是因为MySQL默认关闭了
ONLY_FULL_GROUP_BY严格模式,允许SELECT中出现未包含在GROUP BY子句、也未被聚合函数包裹的字段,实际返回的是该字段的任意匹配值,不符合SQL标准。PostgreSQL严格遵循SQL标准,默认不允许这种语法,所以会抛出报错。
注意:原示例SQL的JOIN条件存在语法错误,ON table1.field1, table2.field1需要修正为ON table1.field1 = table2.field1才可正常运行。
- 方案1:使用聚合函数包裹非GROUP BY字段(兼容标准SQL,最通用)
如果你的需求和MySQL默认逻辑一致,只需要拿到table2.field2的任意匹配值,可以用PostgreSQL10及以上版本支持的ANY_VALUE()函数,和MySQL的逻辑完全对齐:
SELECT table1.field1, ANY_VALUE(table2.field2) AS field2 FROM table1 LEFT JOIN table2 ON table1.field1 = table2.field1 GROUP BY table1.field1;
如果有明确的取值逻辑,比如要最大值、最小值、去重后的列表,可以替换为对应的聚合函数:
-- 取每个group中最大的field2 SELECT table1.field1, MAX(table2.field2) AS field2 FROM table1 LEFT JOIN table2 ON table1.field1 = table2.field1 GROUP BY table1.field1; -- 聚合所有关联的field2为数组 SELECT table1.field1, ARRAY_AGG(DISTINCT table2.field2) AS field2_list FROM table1 LEFT JOIN table2 ON table1.field1 = table2.field1 GROUP BY table1.field1;
- 方案2:使用PostgreSQL特有的
DISTINCT ON语法(适合按单字段去重取指定行)
如果需要控制每个group返回的table2.field2的取值规则(比如取最新插入的关联记录对应的field2),DISTINCT ON语法比GROUP BY更灵活:
SELECT DISTINCT ON (table1.field1) table1.field1, table2.field2 FROM table1 LEFT JOIN table2 ON table1.field1 = table2.field1 -- ORDER BY中第一个字段必须和DISTINCT ON的字段一致,后面的规则用来指定取group中的哪一条 ORDER BY table1.field1, table2.create_time DESC;
- 方案3:利用主键约束省略同表其他字段的GROUP BY声明
如果你要查询的非GROUP BY字段和GROUP BY字段属于同一张表,且GROUP BY字段是该表的主键/唯一键,那么不需要额外处理,PostgreSQL会自动识别依赖关系,不会抛出报错:
-- 假设field1是table1的主键,下面的SQL可以直接运行 SELECT table1.field1, table1.field3, table1.field4 FROM table1 LEFT JOIN table2 ON table1.field1 = table2.field1 GROUP BY table1.field1;
内容的提问来源于stack exchange,提问作者Thiago Bueno Fiorenza
相关产品推荐
相关产品推荐

