当前位置: 首页 > 知识库问答 >
问题:

必须出现在GROUP BY子句中或在聚合函数中使用

祖麻雀
2023-03-14

我有一张桌子看起来像这个叫“Makerar”的人

 cname  | wmname |          avg           
--------+-------------+------------------------
 canada | zoro   |     2.0000000000000000
 spain  | luffy  | 1.00000000000000000000
 spain  | usopp  |     5.0000000000000000

并且我要为每个CNAME选择最大平均数值。

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

我如何解决这个问题?

注意:此表是根据以前的操作创建的视图。

共有1个答案

关玮
2023-03-14

是的,这是一个常见的聚合问题。在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

显示与max值匹配的唯一(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)才能支持此功能...

 类似资料:
  • 试图在一个和中进行一个over(order by Id asc行之间的无界前行和当前行),我试图为每个值获得一个累加和。据我所知:

  • 问题内容: 我在SO上找到了一些主题,但是仍然找不到适合我的查询的设置。 这是查询,在本地主机上运行得很好: 但是在Heroku上,我 遇到了-GROUP BY子句 上面的错误, 或者在聚合函数中使用 。 然后,我在某处读到,我应该指定表中的所有列,因此我尝试了以下操作: 但这在本地主机上不起作用,在Heroku上也不行… 什么是查询的正确配置? 问题答案: 我认为您正在尝试在同一列上进行汇总和分

  • 演示:https://gcc.godbolt.org/z/c33gbqfqh 我在https://en.cppreference.com/w/cpp/language/aggregate_initialization中没有发现任何关于“析构函数”的提及。标准真的要求聚合字段的析构函数对聚合的每个潜在用户都可用吗?

  • 问题内容: 简而言之,我有一个表格,其中除其他外,还包含一个用于时间戳记的列。我想获得具有最新(即最大价值)时间戳的行。目前,我正在这样做: 但是我宁愿做这样的事情: 但是,SQLite拒绝此查询: 该文件证实了这一行为(页面底部): 聚合函数只能在SELECT语句中使用。 我的问题是:是否可以编写查询以获取具有最大时间戳的行,而无需对select进行排序并将返回的行数限制为1?这似乎应该有可能,

  • 是GCC和Clang中的bug,还是标准允许他们接受此代码?

  • 问题内容: 我有此SQL语句,并且SQL Server给我以下错误: 除非聚合不在HAVING子句或选择列表中包含的子查询中,否则它可能不会出现在WHERE子句中。 在where子句中,我只想提取最旧的未付款帐单日期大于DelinquentDaysThreshhold(以天为单位)或PastDueAmount(计算值)大于DelinquentAmountThreshold的记录。 由于某些原因,S