如何在 oracle 数据库中为具有复杂聚合的数据透视编写等效的 sql 查询?
Posted
技术标签:
【中文标题】如何在 oracle 数据库中为具有复杂聚合的数据透视编写等效的 sql 查询?【英文标题】:How can i write an equivalent sql query for pivot with complex aggregations in oracle database? 【发布时间】:2021-03-06 17:22:23 【问题描述】:在 Spark 中,我们可以提供带有枢轴的复杂聚合。 例如
project.groupBy("mgr","job").pivot("job").agg(sum(project.col("salary")).alias("ss") * count("*").alias("c"))
关于以下数据,即项目
mgr | deptno | salary | job |
---|---|---|---|
APAC | 10 | 100 | CLERK |
APAC | 20 | 200 | MANAGER |
APAC | 20 | 300 | CLERK |
APAC | 10 | 400 | CLERK |
JPAC | 20 | 1000 | CLERK |
JPAC | 10 | 2000 | MANAGER |
EMEA | 20 | 10000 | CLERK |
EMEA | 20 | 40000 | MANAGER |
EMEA | 20 | 30000 | CLERK |
输出:
mgr | job | CLERK | MANAGER |
---|---|---|---|
EMEA | MANAGER | null | 40000 |
JPAC | MANAGER | null | 2000 |
EMEA | CLERK | 80000 | null |
JPAC | CLERK | 1000 | null |
APAC | CLERK | 2400 | null |
APAC | MANAGER | null | 200 |
我可以在oracle数据库中使用pivot编写类似的sql查询吗?
【问题讨论】:
工资汇总输出与输入表不匹配。 CLERK 的 EMEA 工资将是 40000(10000+30000)而不是 80000。 它是 Sum * Count right。所以 40000 * 2。 好的,知道了。现在更改我的查询 【参考方案1】:这里有你需要的两个版本(希望两者都能帮助你):
查询#1
select * from (
select mgr,job,salary from project
)
pivot
(
sum(salary)
for job in ('CLERK','MANAGER')
)
输出#1
MGR JOB 'CLERK' 'MANAGER'
JPAC CLERK 1000 -
JPAC MANAGER - 2000
APAC CLERK 800 -
APAC MANAGER - 200
EMEA CLERK 40000 -
EMEA MANAGER - 40000
查询#2:
select * from (
select mgr,job,salary from project
)
pivot
(
sum(salary)
for Job in ('CLERK','MANAGER')
)
输出#2:
MGR 'CLERK' 'MANAGER'
EMEA 40000 40000
APAC 800 200
JPAC 1000 2000
*查询#3 (SUM()COUNT()):
select * from (
select mgr,job,job JobToPivot,sum(salary)*count(*) salary from project
group by mgr,job
)
pivot
(
max(salary)
for JobToPivot in ('CLERK','MANAGER')
)
输出#3:
MGR JOB 'CLERK' 'MANAGER'
JPAC CLERK 1000 -
JPAC MANAGER - 2000
APAC CLERK 2400 -
APAC MANAGER - 200
EMEA CLERK 80000 -
EMEA MANAGER - 40000
*查询#4 (sum()COUNT()):
select * from (
select mgr,job,sum(salary)*count(*) salary from project
group by mgr,job
)
pivot
(
max(salary)
for Job in ('CLERK','MANAGER')
)
输出#4:
MGR 'CLERK' 'MANAGER'
EMEA 80000 40000
APAC 2400 200
JPAC 1000 2000
【讨论】:
在 spark 查询中提供的聚合是 sum(project.col("salary")).alias("ss") * count("*").alias("c")。所以我们在 sql 查询中需要 sum 和 count 两者。 请看一下。 我认为查询 4 需要一些修改,例如可以将别名与 sum(salary) count() 一起使用,并且像 max 这样的一些函数可以在枢轴内作为聚合传递。所以 select * from ( select mgr,job,sum(salary)*count() as sum_count Salary from project group by mgr,job ) pivot ( max(sum_count) for Job in ('CLERK','MANAGER' ) ) 可能是正确的查询。 由于答案是对的,所以没有着急。我已根据您的建议更改了答案。【参考方案2】:您的结果集对我来说没有意义。其中之一不是更有用吗?
select mgr, job, sum(salary)
from project
group by mgr, job;
这会为每个 mgr
和 job
创建一个单独的行,但只有一个薪水。
或者:
select mgr,
sum(case when job = 'CLERK' then salary end) as clerk,
sum(case when job = 'MANAGER' then salary end) as manager
from project
group by mgr;
每个mgr
有一行,两个薪水列中都填充了薪水。
这两个都是标准 SQL(与 pivot
不同),应该在任何数据库中运行。
【讨论】:
你是对的。我们可以在不使用 pivot 关键字的情况下使用(聚合+过滤器)实现数据透视。这将适用于任何数据库。如果我们可以在 sql 中提供带有枢轴的复杂聚合,我想做的就像 spark 一样。以上是关于如何在 oracle 数据库中为具有复杂聚合的数据透视编写等效的 sql 查询?的主要内容,如果未能解决你的问题,请参考以下文章