must appear in the GROUP BY clause or be used in an aggregate function
我有一张桌子,看起来像这个调用方" makerar"
1 2 3 4 5 | cname | wmname | avg --------+-------------+------------------------ canada | zoro | 2.0000000000000000 spain | luffy | 1.00000000000000000000 spain | usopp | 5.0000000000000000 |
我想为每个cname选择最大平均。
1 | SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname; |
但是我会出错
1 2 | 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; |
所以我这样做
1 | SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname, wmname; |
但是,这不会给出预期的结果,并且下面显示了错误的输出。
1 2 3 4 5 | cname | wmname | MAX --------+--------+------------------------ canada | zoro | 2.0000000000000000 spain | luffy | 1.00000000000000000000 spain | usopp | 5.0000000000000000 |
实际结果应为
1 2 3 4 | cname | wmname | MAX --------+--------+------------------------ canada | zoro | 2.0000000000000000 spain | usopp | 5.0000000000000000 |
我该如何解决这个问题?
注意:此表是根据上一个操作创建的VIEW。
是的,这是一个常见的聚合问题。在SQL3(1999)之前,所选字段必须出现在
要变通解决此问题,您必须在子查询中计算聚合,然后将其自身与之合并以获得您需要显示的其他列:
1 2 3 4 5 6 7 8 9 10 11 12 | 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 |
但是您也可以使用窗口函数,它看起来更简单:
1 2 3 | SELECT cname, wmname, MAX(avg) OVER (PARTITION BY cname) AS mx FROM makerar ; |
此方法唯一的作用是它将显示所有记录(窗口功能不分组)。但是它会在每行中显示正确的国家(即在
1 2 3 4 5 | cname | wmname | mx --------+--------+------------------------ canada | zoro | 2.0000000000000000 spain | luffy | 5.0000000000000000 spain | usopp | 5.0000000000000000 |
仅显示与最大值匹配的
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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开始,管理员需要在服务器配置中手动启用此选项(
在Postgres中,您还可以使用特殊的
1 2 3 4 5 6 | SELECT DISTINCT ON (cname) cname, wmname, avg FROM makerar ORDER BY cname, avg DESC ; |
在
但是,有一种解决方法:也将必填字段汇总在一起。
在posgres中,这应该起作用:
1 2 | SELECT cname, (array_agg(wmname ORDER BY avg DESC))[1], MAX(avg) FROM makerar GROUP BY cname; |
请注意,这会创建一个由wg排序的所有wname的数组,并返回第一个元素(postgres中的数组基于1)。
1 2 3 4 5 6 | SELECT t1.cname, t1.wmname, t2.max FROM makerar t1 JOIN ( SELECT cname, MAX(avg) MAX FROM makerar GROUP BY cname ) t2 ON t1.cname = t2.cname AND t1.avg = t2.max; |
使用
1 2 3 4 5 6 | SELECT cname, wmname, avg FROM ( SELECT cname, wmname, avg, rank() OVER (PARTITION BY cname ORDER BY avg DESC) FROM makerar) t WHERE rank = 1; |
注意
任一将在每个组中保留多个最大值。如果即使每条记录中只有多条记录且平均avg等于max,则应检查@ypercube的答案。
对我而言,这与"常见的聚合问题"无关,而仅与错误的SQL查询有关。唯一正确的答案是"为每个名称选择最大平均..."
1 | SELECT cname, MAX(avg) FROM makerar GROUP BY cname; |
结果将是:
1 2 3 4 | cname | MAX(avg) --------+--------------------- canada | 2.0000000000000000 spain | 5.0000000000000000 |
该结果通常回答以下问题:"每个组的最佳结果是什么?"。我们看到,西班牙的最佳结果是5,而加拿大的最佳结果是2。这是事实,没有错误。
如果还需要显示wmname,则必须回答以下问题:"从结果集中选择wmname的规则是什么?"让我们稍微更改输入数据以澄清错误:
1 2 3 4 5 | cname | wmname | avg --------+--------+----------------------- spain | zoro | 1.0000000000000000 spain | luffy | 5.0000000000000000 spain | usopp | 5.0000000000000000 |
您对以下查询的运行期望什么结果:
换句话说,"谁在
这似乎也很好
1 2 3 4 5 6 | SELECT * FROM makerar m1 WHERE m1.avg = (SELECT MAX(avg) FROM makerar m2 WHERE m1.cname = m2.cname ) |
我最近在尝试使用
1 2 3 4 5 6 | SELECT DATE(dateday) AS pick_day, COUNT(CASE WHEN (apples = 'TRUE' OR oranges 'TRUE') THEN fruit END) AS fruit_counter FROM pickings GROUP BY 1 |
而不是使用-在后者中,我遇到了错误:苹果和橘子应该出现在集合函数中
1 | CASE WHEN ((apples = 'TRUE' OR oranges 'TRUE') THEN COUNT(*) END) END AS fruit_counter |