SQL:查询作为子查询或 CTE 写入的总和的最大值失败

问题描述 投票:0回答:3

假设一个表salaries包含employee_iddepartment_idsalary,如下。

e_id | dpt_id | salary
---- | ------ | ------
   1 |      2 |   1000
   2 |      2 |   2000
   3 |      5 |   3000
   4 |      6 |    500
   5 |      5 |    100
   6 |      1 |   1050

我想为 dpt 提供最高/最低工资,我使用了以下查询,但失败了:

select sum_sal_per_dpt.dpt_id, max(sum_sal_per_dpt.total_salaries)
from (
      select dpt_id, sum(salary) as total_salaries
      from salaries
      group by dpt_id ) as sum_sal_per_dpt
group by sum_sal_per_dpt.dpt_id
union
select sum_sal_per_dpt.dpt_id, min(sum_sal_per_dpt.total_salaries)
from (
      select dpt_id, sum(salary) as total_salaries
      from salaries
      group by dpt_id ) as sum_sal_per_dpt
group by sum_sal_per_dpt.dpt_id

我得到的输出是一个包含 dpt_id 和工资总和的表,就好像只执行了子查询一样:

dpt_id | salary
------ | ------
     2 |   3000
     5 |   3100
     6 |    500
     1 |   1050

而不是

dpt_id | salary
------ | ------
     5 |   3100
     6 |    500

如果我以 CTE 方式编写它,也是一样的。

with
sum_sal_per_dpt as (select dpt_id, sum(salary) as total_salaries
                    from salaries
                    group by dpt_id)
select sum_sal_per_dpt.dpt_id, max(sum_sal_per_dpt.total_salaries)
from sum_sal_per_dpt
group by sum_sal_per_dpt.dpt_id
union
select sum_sal_per_dpt.dpt_id, min(sum_sal_per_dpt.total_salaries)
from sum_sal_per_dpt
group by sum_sal_per_dpt.dpt_id

有人可以解释一下吗?

sql database postgresql common-table-expression
3个回答
3
投票

与鲍里斯·约万诺维奇的答案基本相同,只是没有工会。

with
sum_sal_per_dpt as (select dpt_id, sum(salary) as total_salaries
                    from salaries
                    group by dpt_id)

SELECT dpt_id, total_salaries
FROM sum_sal_per_dpt
WHERE 
total_salaries = ( SELECT max(total_salaries) FROM sum_sal_per_dpt )
OR 
total_salaries = ( SELECT min(total_salaries) FROM sum_sal_per_dpt );

结果:

dpt_id 总工资
5 3100
6 500

DB-Fiddle.uk

上的示例

为什么您的初始查询不起作用:

您总是会退回到使用“GROUP BY”并指示 DBMS 按 dpt_id 聚合您的结果。 所以它永远不会整理任何部门 ID。

Max(XYZ) 不是一个过滤/聚合函数,只能为您提供列的最大值以及该最大值的所有相应字段。
它将为您提供每个不同行的最大值 - 其中区别是由您在 GROUP BY 子句

中引用的列定义的

如果您将第一个查询更改为仅给出最大/最小值,您可以看到这些值已经存在 - 只是无法使用。

select max(sum_sal_per_dpt.total_salaries), min(sum_sal_per_dpt.total_salaries)
from (
      select dpt_id, sum(salary) as total_salaries
      from salaries
      group by dpt_id ) as sum_sal_per_dpt
最大 分钟
3100 500

我刚刚应用了官方 postgres 文档中的聚合门教程中的解决方案。
Postgres 聚合文档


2
投票

以下内容应该会给您带来预期的结果:

;with data as
(
select dpt_id, sum(salary) as total_salaries
from salaries
group by dpt_id
)
select dpt_id, total_salaries
from data 
where total_salaries = (select max(total_salaries) from data)
union 
select dpt_id, total_salaries
from data 
where total_salaries = (select min(total_salaries) from data)

请注意,如果您有多个最大值和/或最小值,上面的代码将为您提供多行,您可以根据您想要看到的内容轻松调整它。

在您的代码中,您使用的是

dpt_id
分组,这就是为什么您仍然获得每个
dpt_id
的最大值,因此多行,使用
union
而不是
union all
可能会造成额外的混乱,这将删除两个表中相同的行。


2
投票

您可以使用

ROW_NUMBER()
来识别行。然后过滤就很容易了。例如:

select *
from (
  select dpt_id, sum(salary) as ts,
    row_number() over(order by sum(salary)) as rn,
    row_number() over(order by sum(salary) desc) as rnd
  from t
  group by dpt_id
) x
where rn = 1 or rnd = 1

结果:

 dpt_id  ts    rn  rnd 
 ------- ----- --- --- 
 6       500   1   4   
 5       3100  4   1   

参见小提琴

© www.soinside.com 2019 - 2024. All rights reserved.