3 回答
TA贡献1860条经验 获得超8个赞
是的,这是一个常见的聚合问题。在SQL3(1999)之前,所选字段必须出现在GROUP BY子句[*]中。
要变通解决此问题,您必须在子查询中计算聚合,然后将其自身与之合并以获得您需要显示的其他列:
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
;
cname | wmname | mx
--------+--------+------------------------
canada | zoro | 2.0000000000000000
spain | usopp | 5.0000000000000000
但是您也可以使用窗口函数,它看起来更简单:
SELECT cname, wmname, MAX(avg) OVER (PARTITION BY cname) AS mx
FROM makerar
;
此方法唯一的作用是它将显示所有记录(窗口功能不分组)。但是它将在每行中显示正确的国家(即cname最高级别)MAX,由您决定:
cname | wmname | mx
--------+--------+------------------------
canada | zoro | 2.0000000000000000
spain | luffy | 5.0000000000000000
spain | usopp | 5.0000000000000000
仅显示(cname, wmname)与最大值匹配的元组的解决方案(可能不太优雅)是:
SELECT DISTINCT /* distinct here matters, because maybe there are various tuples for the same max value */
m.cname, m.wmname, t.avg AS mx
FROM (
SELECT cname, wmname, avg, ROW_NUMBER() OVER (PARTITION BY avg DESC) AS rn
FROM makerar
) t JOIN makerar m ON m.cname = t.cname AND m.wmname = t.wmname AND t.rn = 1
;
cname | wmname | mx
--------+--------+------------------------
canada | zoro | 2.0000000000000000
spain | usopp | 5.0000000000000000
[*]:有趣的是,尽管规范允许选择未分组的字段,但主要引擎似乎并不真正喜欢它。Oracle和SQLServer根本不允许这样做。Mysql以前默认情况下允许它,但是现在从5.7开始,管理员需要ONLY_FULL_GROUP_BY在服务器配置中手动启用此选项()以支持此功能...
TA贡献1993条经验 获得超5个赞
在Postgres中,您还可以使用特殊DISTINCT ON (expression)语法:
SELECT DISTINCT ON (cname)
cname, wmname, avg
FROM
makerar
ORDER BY
cname, avg DESC ;
TA贡献1796条经验 获得超4个赞
在selects中指定非分组字段和非聚合字段的问题group by在于,在这种情况下,引擎无法知道应该返回哪个记录的字段。首先吗 最后吗?通常没有自然与汇总结果相对应的记录(min并且max是例外)。
但是,有一种解决方法:也将必填字段汇总在一起。在posgres中,这应该起作用:
SELECT cname, (array_agg(wmname ORDER BY avg DESC))[1], MAX(avg)
FROM makerar GROUP BY cname;
请注意,这会创建一个由wg排序的所有wname的数组,并返回第一个元素(postgres中的数组基于1)。
- 3 回答
- 0 关注
- 7171 浏览
添加回答
举报