2010-01-04 58 views
6

我有一個棘手的情況,試圖從多個查詢中獲取信息到單個行中。如何將兩個查詢(union all)合併爲一行?

考慮下表:

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)在報告中的章節下面每一行應該影響。

我需要一個查詢,可以爲每個用戶組返回一行,但只有一個附帶條件。 JobsCpu的值必須根據子系統ID進入不同列,我只對SYS7NORM子系統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行,兩者或兩者都不是,實現此目標的最佳方法是什麼?

我想過從外部選擇子表中查詢子表,但這可能會有性能方面的影響。

此外,這將是一個痛苦,因爲我不得不使外部查詢包括規範和SYS7子系統然後運行一個子查詢場(我不能讓外部查詢只是NORM工作,因爲只有SYS7行的組的存在不會被這種方式捕獲)。

你可以編織任何你的左中 - 內越位加入魔法來提出一個可行的解決方案嗎?

我更喜歡與供應商無關的解決方案,但如果您必須轉到供應商特定的平臺,那麼該平臺就是DB2。儘管如此,其他平臺至少可以給我一些想法,讓我很高興看到它們。

+0

如果你測試和比較的解決方案,我很想看看結果。本能地,我期望任何解決方案以某種方式執行CASE聲明的任務。即「如果groupname = g且subsys = s,則添加到聚合(g,s)」。我期望在數據檢索方面有更多的不同。但是,我很樂意看到DBMS可以利用索引信息來減少彙總某些組所需的比較次數。我建議你在你的物理排序順序(聚簇索引)是(subsys,groupname)的測試排列中加入。 – 2010-01-05 17:25:30

回答

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 
+0

我擔心必須爲主查詢中的每個組執行子查詢,但是您的解決方案似乎已經避開了這個問題。看起來它只是兩個子查詢,不管有多少個組。感謝您的意見,我一定會爲此投入一次。 – paxdiablo 2010-01-04 06:21:06

+0

+1並接受。這個在數據庫中只用了兩次,並且足夠滿足我的需求。儘管我已經對它進行了編輯,以匹配DB2的mote嚴格要求,並稍微修改了這個聯合。 – paxdiablo 2010-01-04 07:03:53

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+。

+0

這絕對是比我更好的解決方案;我不知道這個'關鍵',謝謝你的分享! – 2010-01-04 04:56:27

+0

您的SUM應該封裝整個CASE,因爲子系統不是GROUP的一部分。見http://stackoverflow.com/questions/1997519/how-do-i-combine-two-queries-union-all-into-one-row/1997581#1997581 – 2010-01-04 05:07:47

+0

@克雷格:更正,thanx。 – 2010-01-04 05:15:34

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 
+0

+1:正確的SUM CASE格式。 – 2010-01-04 05:16:50

+0

與@ OMG的回答一樣,我擔心所有那些每行功能的東西。我必須檢查一下。我不認爲最後兩筆錢是必要的,因爲我不關心「OtherXxx」信息,只是NORM和SYS7。謝謝,我需要去做一些性能測試。 – paxdiablo 2010-01-04 06:18:33

+0

+1幫助我,但@ BlueRaja的解決方案工作正常,只有兩個在數據庫刷卡,所以我不需要測試其他解決方案。我會盡快進行測試,因爲我想一勞永逸地找出這些每行函數是否足夠快。謝謝你的幫助。 – paxdiablo 2010-01-04 07:21:14