首页 > 解决方案 > PostgreSQL 会自动检测 group by 子句中的唯一记录吗?

问题描述

在 PostgreSQL 中是否不需要将唯一列添加到 group by 子句中?

我通常使用 Microsoft SQL Server,我们必须将所有需要的列添加到 group by 子句中。

PostgreSQL 查询:

DROP TABLE IF EXISTS temp_invoice_detail;
CREATE TEMP TABLE temp_invoice_detail(
    invoice_id integer,
    item_id integer,
    qty integer,
    warehouse_id integer    
);

ALTER TABLE temp_invoice_detail ADD CONSTRAINT temp_invoice_detail_result_pkey PRIMARY KEY (invoice_id, item_id);

insert into temp_invoice_detail (invoice_id, item_id, qty, warehouse_id) values (1, 1, 100, 1);
insert into temp_invoice_detail (invoice_id, item_id, qty, warehouse_id) values (1, 2, 200, 1);
insert into temp_invoice_detail (invoice_id, item_id, qty, warehouse_id) values (2, 1, 100, 1);

select invoice_id, item_id, sum(qty) as total_qty, warehouse_id
from temp_invoice_detail
group by invoice_id, item_id --should I add "warehouse_id" in group by clause?
order by invoice_id, item_id;

DROP TABLE IF EXISTS temp_invoice_detail;

我希望 PostgreSQL 显示错误消息:

列“temp_invoice_detail.warehouse_id”必须出现在 GROUP BY 子句中或在聚合函数中使用

但是查询成功运行并返回 3 条记录(上面插入语句中的所有 3 条记录)。

invoice_id  item_id  total_qty  warehouse_id
1           1        100        1
1           2        200        1
2           1        100        1

在 MS-SQL 中,为了让这个查询可以正常运行,group by 子句必须是:

按 invoice_id、item_id、warehouse_id 分组

标签: postgresqlpostgresql-9.5

解决方案


这是因为您定义invoice_id, item_id为表的主键并且按唯一键分组就足够了,因为向组中添加更多列不会改变分组依据的结果。

从手册中引用

当存在 GROUP BY 或存在任何聚合函数时,SELECT 列表表达式引用未分组列是无效的,除非在聚合函数内或未分组列在功能上依赖于分组列,否则会有更多为未分组的列返回一个可能的值。如果分组列(或其子集)是包含未分组列的表的主键,则存在函数依赖关系

(强调我的)

这实际上是 SQL 标准允许的。Postgres 甚至从 group by 中删除不需要的列(基于主键或唯一键的存在),因为这提高了性能。


推荐阅读