沙滩星空的博客沙滩星空的博客

PostgreSQL使用聚合函数报错 must appear in the GROUP BY clause or be used in an aggregate function

缘起

每个月抓取电商平台某几个类目的商品概要数据。
snapshots 数据表保存不同类目在不同时间的快照列表,一对多,连接 snapshot_products 数据表,可获取一个类目快照下的商品数。

SQL初始版本:

SELECT
snpt.url 快照地址
,snpt.title 快照标题
,snpt.id 快照ID
,count(prodx.id) 快照商品数
,to_char(snpt.created_at, 'yyyy-MM-dd') as 快照时间
from snapshots snpt
join snapshot_products prodx on prodx.snapshot_id = snpt.id
where snpt.site_id = 1573251441454223360
and snpt.created_at > '2023-01-01'
group by 快照地址
;

报错:

ERROR: column "snpt.title" must appear in the GROUP BY clause or be used in an aggregate function

原因

在SQL3(1999)之前,所选字段必须出现在GROUP BY子句[*]中。

聚合查询时,SELECT子句中可以有3种内容:

  • 在GROUP BY子句中出现的列名
  • 使用聚合函数(SUM、MAX、AVG等)
  • 常量

注:MySQL数据库是支持聚合后在SELECT使用原表的列,但最好养成习惯,不要去用。

可以在子查询中计算聚合,然后将其自身与之合并以获得需要显示的其他列.网上示例代码如下:

SELECT m.cname, m.wmname, t.mx
FROM (
    SELECT cname, MAX(avg) AS mx
    FROM makerar
    GROUP BY cname
    ) t JOIN makerar m ON m.cname = t.cname AND t.mx = m.avg
;

还可以使用 窗口函数,看起来更简单:

SELECT cname, wmname, MAX(avg) OVER (PARTITION BY cname) AS mx
FROM makerar
;

解决

根据提示,把 GROUP BY 子句后面的字段补全即可。

SELECT
snpt.url 快照地址
,snpt.title 快照标题
,snpt.id 快照ID
,count(prodx.id) 快照商品数
,to_char(snpt.created_at, 'yyyy-MM-dd') as 快照时间
from snapshots snpt
join snapshot_products prodx on prodx.snapshot_id = snpt.id
where snpt.site_id = 1573251441454223360
and snpt.created_at > '2023-01-01'
group by 快照地址, 快照标题, 快照ID
;

测试发现,GROUP BY 后直接使用 快照ID 字段也行。因为该字段是唯一主键:

group by 快照ID

关于sql:必须出现在GROUP BY子句中或在聚合函数中使用 https://www.codenong.com/19601948/
SQL报错 | column "t1.col_1" must appear in the GROUP BY clause or be used in an aggregate function https://zhuanlan.zhihu.com/p/457341706

未经允许不得转载:沙滩星空的博客 » PostgreSQL使用聚合函数报错 must appear in the GROUP BY clause or be used in an aggregate function

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址