我在尝试将多个查询中的信息整合到一行时遇到了一个棘手的情况。
考虑下表:
CpuUage:
Time time
Group char(10)
Subsys char(4)
Jobs int
Cpu int
持有以下数据:
Time Group Subsys Jobs Cpu
----- ------ ------ ---- ---
00:00 group1 NORM 1 101 (grp1-norm) A1
01:00 group1 SYS7 3 102 (grp1-sys7) A2
01:00 group1 NORM 5 104 (grp1-norm) A1
02:00 group1 NORM 7 108 (grp1-norm) A1
02:00 group2 NORM 9 116 (grp2-norm) B1
02:00 group3 SYS7 11 132 (grp3-sys7) C2
03:00 group1 SYS7 13 164 (grp1-sys7) A2
03:00 group1 IGNR 99 228 (grp1-ignr) --
右侧的标记(例如A1
)是下面报告中每行应该影响的部分。
我需要一个查询,可以为每个用户组返回一行但有一个附带条件。 Jobs
和Cpu
的值必须根据子系统ID进入不同的列,我只对SYS7
和NORM
子系统ID感兴趣。
因此,例如,我们需要以下内容(A/B/1/2
位是回溯到上面行的交叉引用):
<------ 1 ------> <------ 2 ------>
Group NormJobs NormCpu Sys7Jobs Sys7Cpu
------ -------- ------- -------- -------
A: group1 13 313 16 266
B: group2 9 116 0 0
C: group3 0 0 11 164
我们的旧报告解决方案可以运行多个查询(使用union all
),然后对行进行后处理以组合具有相同组名的行,以便:
Group NormJobs NormCpu Sys7Jobs Sys7Cpu
------ -------- ------- -------- -------
group1 13 313 0 0
group1 0 0 16 266
按照以下方式合并在一起:
select groupname, sum(jobs), sum(cpu), 0, 0 from tbl
where subsys = 'NORM'
group by groupname
union all
select groupname, 0, 0, sum(jobs), sum(cpu) from tbl
where subsys = 'SYS7'
group by groupname
不幸的是,我们的新解决方案不允许进行后期处理,而且必须在SQL查询中完成。
请注意,可能存在SYS7
行,NORM
行,两者或两者都没有的群组,实现此目标的最佳方法是什么?
我考虑过从外部选择中查询表格,但可能会产生性能影响。
此外,这将是一个痛苦,因为我必须使外部查询包括NORM和SYS7子系统然后运行每个字段的子查询(我不能只是外部查询对于NORM
个作业,因为只有SYS7
行的组不会被捕获。
你是否可以编织你的左中间内侧越位魔法来提出可行的解决方案?
我更喜欢与供应商无关的解决方案,但是,如果您必须特定于供应商,则该平台是DB2。不过,其他平台至少可以给我一些尝试的想法,所以我很高兴看到它们。
答案 0 :(得分:13)
我不明白子查询的问题,看起来它应该同样快:
select
sub.gn as groupname,
sum(sub.nj) as NormJobs, sum(sun.nc) as NormCpu,
sum(sub.sj) as Sys7Jobs, sum(sub.sc) as Sys7Cpu
from (
select
groupname as gn,
sum(jobs) as nj, sum(cpu) as nc,
0 as sj, 0 as sc
from tbl
where subsys = 'NORM'
group by groupname
union all select
groupname as gn,
0 as nj, 0 as nc,
sum(jobs) as sj, sum(cpu) as sc
from tbl
where subsys = 'SYS7'
group by groupname
) as sub
group by sub.gn
order by 1
答案 1 :(得分:5)
这是一个数据透视表查询。 (如果您需要更多信息,请搜索。)
您想要的查询结构类似于以下内容:
SELECT groupname,
SUM(CASE WHEN subsys = 'NORM' THEN jobs ELSE 0 END) AS NormJobs,
SUM(CASE WHEN subsys = 'NORM' THEN cpu ELSE 0 END) AS NormCpu,
SUM(CASE WHEN subsys = 'SYS7' THEN jobs ELSE 0 END) AS Sys7Jobs,
SUM(CASE WHEN subsys = 'SYS7' THEN cpu ELSE 0 END) AS Sys7Cpu,
SUM(CASE WHEN subsys NOT IN ('NORM', 'SYS7') THEN jobs ELSE 0 END) AS OtherJobs,
SUM(CASE WHEN subsys NOT IN ('NORM', 'SYS7') THEN cpu ELSE 0 END) AS OtherCpu
FROM ???
GROUP BY groupname
答案 2 :(得分:4)
这是一个典型的数据透视查询 - 这是您使用CASE statements执行此操作的方式:
SELECT t.group,
SUM(CASE
WHEN t.subsys = 'NORM' THEN t.jobs
ELSE NULL
END CASE) AS NormJobs,
SUM(CASE
WHEN t.subsys = 'NORM' THEN t.cpu
ELSE NULL
END CASE) AS NormCpu,
SUM(CASE
WHEN t.subsys = 'SYS7' THEN t.jobs
ELSE NULL
END CASE) AS Sys7Jobs,
SUM(CASE
WHEN t.subsys = 'SYS7' THEN t.cpu
ELSE NULL
END CASE) AS Sys7Cpu
FROM CPUUSAGE t
GROUP BY t.group
不幸的是,当Oracle / SQL Server / MySQL / Postgres没有时,DB2的CASE语句需要以END CASE
结束。好吧,PLSQL支持END CASE
...
还有PIVOT syntax,Oracle 11g和SQL Server 2005 +也支持它。