我有一个类似调用者makerar的表格
cname | wmname | avg
--------+-------------+------------------------
canada | zoro | 2.0000000000000000
spain | luffy | 1.00000000000000000000
spain | usopp | 5.0000000000000000
我想为每个cname选择最大的avg。
SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname;
但是我会得到一个错误,
ERROR: column "makerar.wmname" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname;
所以我这样做
SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname, wmname;
然而,这不会给出预期的结果,下面显示了不正确的输出。
cname | wmname | max
--------+--------+------------------------
canada | zoro | 2.0000000000000000
spain | luffy | 1.00000000000000000000
spain | usopp | 5.0000000000000000
实际结果应为
cname | wmname | max
--------+--------+------------------------
canada | zoro | 2.0000000000000000
spain | usopp | 5.0000000000000000
我该如何着手解决这个问题呢?
注意:这个表是在前面的操作中创建的VIEW。
是的,这是一个常见的聚合问题。在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)来支持这个特性…