2016-08-01 62 views
2

我想創建一個表,其中各列的條目都'旋轉'到列標題中。該表僅用於報告目的 - 我的用戶希望通過Excel查詢數據(使用Microsoft Query),問題是在Excel中執行pivoting操作會使文件不切實際地大而慢,即使對於中等大小的數據集(〜100k個數據點)。Oracle SQL:在多個列/字段上旋轉

請看下面的例子:

CREATE TABLE tt 
( 
    "COMMODITY" VARCHAR2(4000 BYTE), 
    "MARKET" VARCHAR2(4000 BYTE), 
    "BID_ASK" VARCHAR2(4000 BYTE), 
    "PRICE"  NUMBER 
); 

INSERT INTO tt VALUES ('Gold','US','Ask',1.1); 
INSERT INTO tt VALUES ('Gold','US','Bid',1); 
INSERT INTO tt VALUES ('Gold','EU','Ask',1.2); 
INSERT INTO tt VALUES ('Gold','EU','Bid',1.1); 
INSERT INTO tt VALUES ('Oil','US','Ask',11); 
INSERT INTO tt VALUES ('Oil','US','Bid',10); 
INSERT INTO tt VALUES ('Oil','EU','Ask',12); 
INSERT INTO tt VALUES ('Oil','EU','Bid',11); 

,我想實現會是這樣的輸出(確切的列標題沒有多大關係):

COMMODITY 'US_Bid' 'US_Ask' 'EU_Bid' 'EU_Ask' 
Gold   1   1.1   1.1  1.2 
Oil   10   11   11   12 

現在是簡單以樞轉單個列:

SELECT * FROM 
(
    SELECT * FROM tt 
) 
PIVOT 
(
    SUM(PRICE) 
    FOR MARKET IN ('US','EU') 
) 

其中給出:

COMMODITY BID_ASK 'US' 'EU' 
Gold  Bid  1  1.1 
Oil   Bid  10  11 
Oil   Ask  11  12 
Gold  Ask  1.1 1.2 

根據我的研究,沒有直接旋轉多列的語法。有一些相關的問題(here,herehere),但我無法找到我的問題的直接答案。所以我想出了以下解決方案:

SELECT * FROM 
(
    SELECT COMMODITY, CONCAT(CONCAT(MARKET,'_'),BID_ASK) AS MARKET_BID_ASK, PRICE FROM tt 
) 
PIVOT 
(
    SUM(PRICE) 
    FOR MARKET_BID_ASK IN ('US_Bid','US_Ask','EU_Bid','EU_Ask') 
) 

這產生了正好所需的輸出。然而,我不認爲這是一個實際的解決方案,因爲我必須輸入的變量數量增長過快(在我的真實數據集中,我想一次旋轉更多的字段,所有這些字段都有許多不同的值)。我知道存在dynamic pivots,但是我不確定這是否適用於Excel,並且我還希望保持語法儘可能簡單,因爲用戶將自己定義查詢(我只是想提供一個模板查詢他們可以適應)。於是,我就查詢IN子句中的字段名稱:

SELECT * FROM 
(
    SELECT COMMODITY, CONCAT(CONCAT(MARKET,'_'),BID_ASK) AS MARKET_BID_ASK, PRICE FROM tt 
) 
PIVOT 
(
    SUM(PRICE) 
    FOR MARKET_BID_ASK IN 
    (
    SELECT DISTINCT CONCAT(CONCAT(MARKET,'_'),BID_ASK) AS MARKET_BID_ASK FROM tt 
) 
) 

我認爲這樣的解決方案可能是可行的,因爲人們仍然會限制查詢的變量,而無需使用列表中喜歡 - 所有級聯選項子查詢中的條件。然而,即使這個查詢中的子查詢應該合法,根據我發現的documentation,我得到了一個「ORA-00936 - 缺少表達式」的錯誤。

+0

請參閱此鏈接http://stackoverflow.com/questions/38651147/how-to-transpose-column-into-row-in-oracle-sql-11g/38653133#38653133並嘗試與** select * from table(pivot(Q'$ SELECT COMMODITY,CONCAT(CONCAT(MARKET,'_'),BID_ASK)作爲MARKET_BID_ASK,價格從tt $'))** –

+0

動態Sql正是您需要轉動字段時的方式這是用戶在運行時定義的。創建一個VBA函數,它將根據用戶選擇構建Sql命令文本。 – Serg

+2

我認爲你找到的「文檔」不正確。如果您查閱[官方文檔](https://docs.oracle.com/database/121/SQLRF/statements_10002.htm#CHDFAFIE),您會發現子查詢選項只能與XML關鍵字結合使用。 – jpw

回答

4

您可以通過內附的列上多列轉動,和值集,在括號:

SELECT * FROM 
(
    SELECT * FROM tt 
) 
PIVOT 
(
    SUM(PRICE) 
    FOR (MARKET, BID_ASK) 
    IN (('US', 'Bid') us_bid, ('US', 'Ask') us_ask, ('EU', 'Bid') eu_bid, ('EU', 'Ask') eu_ask) 
); 

COMMODITY  US_BID  US_ASK  EU_BID  EU_ASK 
---------- ---------- ---------- ---------- ---------- 
Gold    1  1.1  1.1  1.2 
Oil    10   11   11   12 

但值對仍然必須知道,當查詢被解析,這並未」如果你有很多值的組合,就很好。

您唯一的選擇是動態SQL,如您所懷疑的,除非您可以讓Excel處理XML數據透視的結果 - 我認爲這是不可能的。使用動態SQL,如果Excel發現比樞軸查詢更易於處理,則可以具有執行查詢和數據透視並返回引用遊標的函數。