为什么 MAX() 的 SUM() 给出错误的输出?

bab*_*abu 3 mysql aggregate

我有一个餐桌员工

id    name   salary  city
1     ram    50000   c1
2     sham   20000   c2
3     jadu   80000   c1
4     madhu  90000   c4
5     hari   10000   c2
6     gopal  34000   c3
7     komal  55000   c3
8     bappa  98000   c4
Run Code Online (Sandbox Code Playgroud)

查询哪个城市的收入最高。我试过

SELECT city, SUM(salary) AS maxSalary 
FROM employee GROUP BY city ORDER BY salary DESC LIMIT 1;
Run Code Online (Sandbox Code Playgroud)

它工作正常,但如果有多个最大收入城市,那么它不会输出其他最大城市,只输出第一个。

所以我试过这个查询

SELECT city, MAX(totalSalary) maxSalary 
FROM( SELECT city, SUM(salary) AS totalSalary FROM employee GROUP BY city  ) AS tempTable
Run Code Online (Sandbox Code Playgroud)

它正在给予

city  max
c1    188000
Run Code Online (Sandbox Code Playgroud)

但正确的是

city  max
c4    188000
Run Code Online (Sandbox Code Playgroud)

这意味着它正在输出表的第一个城市名称,c1但不是正确的最大收入城市名称,即c4. 什么是正确的查询?

mir*_*173 5

您向数据库发送了错误的查询。您遇到了手册中描述的 mysql 扩展。像这样的查询

SELECT city, MAX(salary) 
from employee
Run Code Online (Sandbox Code Playgroud)

在标准 SQL 中不起作用。它在Oracle 中引发错误(错误消息:“ORA-00937:不是单组组函数”),在MSSqlServer 2012 中(错误消息:“列'employee.city' 在选择列表中无效,因为它未包含在内)在聚合函数或 GROUP BY 子句中”)或postgresql(错误消息:“错误:列“employee.city”必须出现在 GROUP BY 子句中或用于聚合函数中”)。

在选择列表中的标准 SQL 表达式中,只能是也在 group by 子句和聚合函数中使用的列的表达式。group by 子句中使用的列值对于这些组中的所有行都相同。聚合对于一个组也是唯一的。选择为每个组返回一行,其中包含该组的唯一定义值。

如果聚合查询没有 group by 子句,则只有一组行。

该标准不允许在聚合查询的选择列表中使用任意列,因为它的值不是唯一定义的:该列对于查询的行具有不同的值,因此查询应该为该组返回哪一个?

在 mysql 中有一个扩展,如果表达式中的列(不是聚合函数表达式中的列)不在 group by 子句中,则该组的 select 语句返回的值是该组的任意行。

所以查询

SELECT city, MAX(salary) 
from employee
Run Code Online (Sandbox Code Playgroud)

返回所有员工的工资和其中一行所在城市的总和。但是查询只返回一个记录,因为它是一个聚合查询,并且只有一个组包含员工表中的所有记录。

查询

SELECT city, MAX(salary) 
from employee
group by city
Run Code Online (Sandbox Code Playgroud)

为每个城市返回一行,其中包含城市和每个城市的工资。

查询

SELECT city, salary
from employee
group by city
Run Code Online (Sandbox Code Playgroud)

返回每个城市的行和该城市任意雇员的礼节。服务器决定选择哪个城市的雇员。

查询

SELECT city, zipcode
from employee
group by city
Run Code Online (Sandbox Code Playgroud)

还为每个城市返回一行,并带有该城市的邮政编码。如果我们假设每个城市只有一个邮政编码,那么城市定义的每个组的行都包含相同的邮政编码。因此独立于服务器选择重新调整的邮政编码将始终是城市的邮政编码。

在标准 SQL 中,此查询将写为

SELECT city, zipcode
from employee
group by city, zipcode 
Run Code Online (Sandbox Code Playgroud)

创造预期的结果

group by city,zipcodegroup city定义相同的组,因为 zipcdoe 一个城市之间是一一对应的。


查询

SELECT city, SUM(salary) 
from employee
group by city
Run Code Online (Sandbox Code Playgroud)

将不仅包含所需的行,而且包含更多。

一种从此查询中过滤掉所需行的方法如下

SELECT city, SUM(salary) 
from employee
group by city 
having SUM(salary) >= all (select SUM(salary)  city_salary 
     from employee
     group by city)
Run Code Online (Sandbox Code Playgroud)

还有其他过滤方法。

可以通过以下查询找到最大的工资总额

select MAX(city_salary)  
   from (select SUM(salary)  city_salary 
     from employee
     group by city) tab
Run Code Online (Sandbox Code Playgroud)

(注意:在 Oracle 中同样可以通过

select MAX(SUM(salary))  city_salary 
  from employee
  group by city
Run Code Online (Sandbox Code Playgroud)

)

所以我们可以用它来过滤掉需要的:

SELECT city, SUM(salary) 
from employee
group by city 
having SUM(salary) = (select MAX(city_salary)  
   from (select SUM(salary)  city_salary 
     from employee
     group by city) tab) 
Run Code Online (Sandbox Code Playgroud)

@Mihai 在他的评论中已经提出了这个解决方案。