2008-10-17 38 views
4

我正在嘗試從幾個數據庫表生成報表。簡化版本看起來像這樣在SQL中「旋轉」一個表(即交叉製表/交叉製表)

Campaign 
---------- 
CampaignID 

Source 
----------------------- 
Source_ID | Campaign_ID 

Content 
--------------------------------------------------------- 
Content_ID | Campaign_ID | Content_Row_ID | Content_Value 

報告需要讀這樣的:

CampaignID - SourceID - ContentRowID(Value(A)) - ContentRowID(Value(B)) 

凡ContentRowID(價值(A))的意思是「找到一個行已給定的CampaignID和ContentRowId 「A」,然後拿到ContentValue該行的」

從本質上講,我有‘支點’(我認爲這是正確的術語)的行轉換成列...

這是一個Oracle 10g數據庫...

有什麼建議嗎?

+0

你能不能給我們一些樣本數據或告訴我們更多關於限制?例如,對於給定的campaignid,是否只有兩行? – 2008-10-17 19:32:53

+0

contentid和contentrowid有什麼區別? – 2008-10-17 19:43:51

+0

我剛剛發佈了一個應該希望清楚的例子...讓我知道如果這沒有幫助... – Kivus 2008-10-17 20:00:13

回答

1

這是我第一次刺傷它。一旦我瞭解了更多關於內容表的內容,就會細化。

首先,你需要一個臨時表:

CREATE TABLE pivot (count integer); 
INSERT INTO pivot VALUES (1); 
INSERT INTO pivot VALUES (2); 

現在,我們已經準備好進行查詢。

SELECT campaignid, sourceid, a.contentvalue, b.contentvalue 
FROM content a, content b, pivot, source 
WHERE source.campaignid = content.campaignid 
AND pivot = 1 AND a.contentrowid = 'A' 
AND pivot = 2 AND b.contentrowid = 'B' 
+0

將答案中添加額外的內容表信息,因爲我不認爲我可以繼續格式化評論...現在寫... – Kivus 2008-10-17 19:48:20

0

如果你有「甲骨文,完整的參考」題爲神色一節,「打開一個表在其一側」。這給出了執行樞紐的詳細示例和說明,儘管我擁有的版本並沒有將它稱爲支點。

「旋轉桌子」的另一個術語是交叉製表。

用於執行交叉製表的最簡單的工具之一是MS Access。如果你有MS Access,並且你可以建立一個從Access數據庫到你的源表的鏈接,你已經到了一半了。

此時,您可以啓動「查詢嚮導」,並要求它爲您構建交叉表查詢。它真的像回答嚮導問你的問題一樣簡單。這個解決方案的不幸的一面是,如果在SQL視圖中查看生成的查詢,您會看到SQL的Access方言特有的一些SQL,並且通常不能在其他平臺上使用。

您也可以從Oracle網站下載一些簡單的分析工具,然後使用其中一種工具爲您執行交叉制訂。

再一次,如果你真的想用SQL來做,「Oracle,Complete Reference」應該可以幫到你。

1

如果您沒有動態數量的列,並且您的數據集不是太大,您可以這樣做......

SELECT CampaignID, SourceID, 
    (SELECT Content_Value FROM Content c 
     WHERE c.Campaign_ID=s.Campaign_ID 
     AND Content_Row_ID = 39100 
     AND rownum<=1) AS Value39100, 
    (SELECT Content_Value FROM Content c 
     WHERE c.Campaign_ID=s.Campaign_ID 
     AND Content_Row_ID = 39200 
     AND rownum<=1) AS Value39200 
FROM Source s; 

對每個添加的Content_Row_ID重複子查詢。

1

要在標準SQL中執行此操作,您需要知道Content_Row_ID的所有不同值,並按不同值進行連接。然後你需要一個不同的Content_Row_ID值。

SELECT CA.Campaign_ID, 
    C1.Content_Value AS "39100", 
    C2.Content_Value AS "39200", 
    C3.Content_Value AS "39300" 
FROM Campaign CA 
    LEFT OUTER JOIN Content C1 ON (CA.Campaign_ID = C1.Campaign_ID 
    AND C1.Content_Row_ID = 39100) 
    LEFT OUTER JOIN Content C2 ON (CA.Campaign_ID = C2.Campaign_ID 
    AND C2.Content_Row_ID = 39200) 
    LEFT OUTER JOIN Content C3 ON (CA.Campaign_ID = C3.Campaign_ID 
    AND C3.Content_Row_ID = 39300); 

隨着不同值的數量變大,此查詢變得太昂貴而無法高效運行。在PL/SQL或應用程序代碼中更簡單地獲取數據並重新格式化可能更容易。

2

比爾Karwin提到這一點,但我認爲這值得指出的很清楚:

SQL不會做你問什麼,所以任何「解決方案」你得到的是將是一個雜牌。

如果您知道,可以肯定,它總是會在Oracle 10運行,那麼肯定的是,沃爾特·米蒂的交叉表可能做到這一點。正確的做法是在查詢和應用程序代碼中使用最簡單的排序順序組合來正確佈置它。

  • 它適用於其它的數據庫系統,
  • 它不會冒任何其他層crapping出來(我記得有與> 255列,例如一個問題的MySQL,你確定你接口庫作爲COPES以及數據庫本身?)
  • 它(通常)並不那麼難。

如果需要,你可以索要Content_Row_ID第一個,然後問你需要什麼行,由CampaignIDContentRowID有序的,這將讓你在左到右各(填充)細胞,逐行命令。


Ps。

有一堆東西,現代人認爲SQL應該有/做的只是不存在。這是一個,生成的範圍是另一個,遞歸閉包,參數ORDER BY,標準化編程語言......這個列表繼續。 (雖然,有一個技巧ORDER BY

1

比爾卡爾文和安德斯Eurenius是正確的,沒有解決方案是直接的,也沒有任何解決方案時,所產生的列值的數量是不知道的。 Oracle 11g在某種程度上可以用the PIVOT operator來簡化它,但這些列仍然需要事先知道,並且不符合您的問題的10g標準。

0

如果你不知道列數了前面只是帶回一個普通的SQL查詢,並使用服務器端代碼像我這裏列出:Filling Datagrid And Sql Query

0

我做了這個SQL的解決方案。我需要的是行數是類的數量,列是每個類的總結,因此,第一列是行的總數,而每個歐列列是每月的總數,最後一行是總結逐月完整的專欄。

好運

Select DS.Cla, 
Sum(case 
when (Extract(year from DS.Data) =:intYear) then DS.PRE 
else 0 
end) as ToTal, 
Sum(case 
when (Extract(month from DS.Data) =1) then DS.PRE 
else 0 
end) as Jan, 
Sum(case 
when (Extract(month from DS.Data) =2) then DS.PRE 
else 0 
end) as FEV, 
Sum(case 
when (Extract(month from DS.Data) =3) then DS.PRE 
else 0 
end) as MAR, 
Sum(case 
when (Extract(month from DS.Data) =4) then DS.PRE 
else 0 
end) as ABR, 
Sum(case 
when (Extract(month from DS.Data) =5) then DS.PRE 
else 0 
end) as MAI, 
Sum(case 
when (Extract(month from DS.Data) =6) then DS.PRE 
else 0 
end) as JUN, 
Sum(case 
when (Extract(month from DS.Data) =7) then DS.PRE 
else 0 
end) as JUL, 
Sum(case 
when (Extract(month from DS.Data) =8) then DS.PRE 
else 0 
end) as AGO, 
Sum(case 
when (Extract(month from DS.Data) =9) then DS.PRE 
else 0 
end) as SETE, 
Sum(case 
when (Extract(month from DS.Data) =10) then DS.PRE 
else 0 
end) as OUT, 
Sum(case 
when (Extract(month from DS.Data) =11) then DS.PRE 
else 0 
end) as NOV, 
Sum(case 
when (Extract(month from DS.Data) =12) then DS.PRE 
else 0 
end) as DEZ 
from Dados DS 
Where DS.Cla > 0 
And Extract(Year from DS.Data) = :intYear 
group by DS.CLA 

Union All 

Select 0*count(DS.cla), 0*count(DS.cla), 
Sum(case 
when (Extract(month from DS.Data) =1) then DS.PRE 
else 0 
end) as JAN, 
Sum(case 
when (Extract(month from DS.Data) =2) then DS.PRE 
else 0 
end) as FEV, 
Sum(case 
when (Extract(month from DS.Data) =3) then DS.PRE 
else 0 
end) as MAR, 
Sum(case 
when (Extract(month from DS.Data) =4) then DS.PRE 
else 0 
end) as ABR, 
Sum(case 
when (Extract(month from DS.Data) =5) then DS.PRE 
else 0 
end) as MAI, 
Sum(case 
when (Extract(month from DS.Data) =6) then DS.PRE 
else 0 
end) as JUN, 
Sum(case 
when (Extract(month from DS.Data) =7) then DS.PRE 
else 0 
end) as JUL, 
Sum(case 
when (Extract(month from DS.Data) =8) then DS.PRE 
else 0 
end) as AGO, 
Sum(case 
when (Extract(month from DS.Data) =9) then DS.PRE 
else 0 
end) as SETE, 
Sum(case 
when (Extract(month from DS.Data) =10) then DS.PRE 
else 0 
end) as OUT, 
Sum(case 
when (Extract(month from DS.Data) =11) then DS.PRE 
else 0 
end) as NOV, 
Sum(case 
when (Extract(month from DS.Data) =12) then DS.PRE 
else 0 
end) as DEZ 
from Dados DS 
Where DS.Cla > 0 
And Extract(Year from DS.Data) = :intYear