2014-07-17 252 views
1

是否可以將下面的Oracle SQL查詢轉換爲動態查詢?我的意思是,我已經硬編碼案例陳述的價值爲'互聯網','銷售'等...是否有可能避免硬編碼?我的源列是動態的。我在想一個for循環和數組,但是在SQL中可用嗎?如果有人能讓我這樣做,那會很好。謝謝。Oracle SQL - 動態case語句

SELECT 
     NVL(status, 'Grand Total') AS "ROW LABELS", 
     COUNT(case when source = 'INTERNET' THEN 1 end) AS "INTERNET", 
     COUNT(case when source = 'SALES' THEN 1 end) AS "SALES", 
     COUNT(case when source = 'DEMO' THEN 1 end) AS "DEMO", 
     COUNT(case when source = 'COM' THEN 1 end) AS "COM", 
     COUNT(CASE WHEN order_source IN ('INTERNET', 'SALES', 'DEMO', 'COM') THEN 1 END) AS "Grand Total" 
FROM 
SOMETABLE 
GROUP BY ROLLUP(status); 
+0

您如何知道在'total'中包含哪些值?或者你是否包括了一切 - 如果這樣的話有點意思。 –

+0

是的,你可以使這個查詢動態。我會動態地使用您正在使用的代碼語言,c#,php等動態構建查詢。如果您不能這樣做,可以在oracle中使用while循環或遊標。讓我們更多地瞭解您的需求,以及您如何確定您的病例陳述中的價值。 – Vulcronos

+1

也許你在問一個PIVOT? – Randy

回答

2

您需要一個具有動態列定義的PIVOT函數。最簡單的方法是支點的xml:

create table tst_data (id int primary key, source varchar2(255)); 

insert into tst_data values (1, 'INTERNET'); 
insert into tst_data values (2, 'DEMO'); 
insert into tst_data values (3, 'INTERNET'); 
insert into tst_data values (4, 'SALES'); 
insert into tst_data values (5, 'INTERNET'); 
insert into tst_data values (6, 'DEMO'); 
insert into tst_data values (7, 'INTERNET'); 
insert into tst_data values (8, 'COM'); 

commit; 

select * from (
    select source from tst_data 
) 
pivot xml 
(
    count(1) 
    for source in (select distinct t.source from tst_data t) 
) 

後,您需要處理XML數據:

<PivotSet> 
    <item> 
     <column name = "SOURCE">COM</column> 
     <column name = "COUNT(1)">1</column> 
    </item> 
    <item> 
     <column name = "SOURCE">DEMO</column> 
     <column name = "COUNT(1)">2</column> 
    </item> 
    <item> 
     <column name = "SOURCE">INTERNET</column> 
     <column name = "COUNT(1)">4</column> 
    </item> 
    <item> 
     <column name = "SOURCE">SALES</column> 
     <column name = "COUNT(1)">1</column> 
    </item> 
</PivotSet> 

PIVOT XML支持動態欄定義(for source in (select distinct t.source from tst_data t)),但是它返回的XML數據。 Extractvaluexmltable函數允許從服務器端的XML中查詢特定的列,但是您必須提前指定字段名稱。所以我假設在客戶端解析它。

如果你想在數據庫層上做所有事情,還有另一種方法。 PIVOT(不是XML)需要列名稱for source in ('INTERNET', 'DEMO', 'COM', ...)。這有可能產生這樣的查詢並返回一個光標到客戶端:

CREATE OR REPLACE FUNCTION FUNCTION1 RETURN SYS_REFCURSOR AS 
cur sys_refcursor; 
BEGIN 
    open cur for 'select * from dual'; // generate PIVOT query here 
    RETURN cur; 
END FUNCTION1; 

我不知道有什麼方法來創建光標一個簡單的無類型查詢(服務器端),所以如果你的願望使用普通SQL查詢分兩步執行:

  1. 在PL/SQL函數中生成具有命名列的PIVOT查詢;
  2. 從客戶端運行查詢。
+0

嘿,我將如何處理XML數據? –

+0

@NomanArain你需要在哪裏?我的意思是你可以在客戶端或服務器端執行它嗎? –

2

你不能在純SQL中做到這一點。你可以創建一個動態生成結果的函數;

create or replace function get_counts return sys_refcursor as 
    query varchar2(32767); 
    rc sys_refcursor; 
begin 
    query := 'select nvl(status, ''Grand Total'') as row_labels'; 
    for tmp in (select distinct source from sometable order by 1) 
    loop 
    query := query || ', count(case when source = ''' || tmp.source 
     || ''' then 1 end) as "' || substr(tmp.source, 1, 30) || '"'; 
    end loop; 
    query := query || ', count(*) as total'; 
    query := query || ' from sometable'; 
    query := query || ' group by rollup(status)'; 
    query := query || ' order by status'; 

    open rc for query; 

    return rc; 
end; 
/

要在SQL * Plus或SQL Developer中運行(與「運行的腳本」):

var rc refcursor; 
exec :rc := get_counts; 
print rc 

你也可以做到這一點的,也許比一個匿名塊就好辦了查詢:

select get_counts from dual; 

在SQL Developer中,顯示在查詢輸出窗口無益水準的展示,但如果您雙擊該值(它看起來像{<ROW_LABELS=...>}),然後編輯圖標出現在最右邊;單擊它,實際值將顯示在新窗口中。

我假設'總'應包括一切;如果不是,我不知道你如何確定動態包含什麼。如果你可以做到這一點,雖然你可以保留一個單獨的變量或集合,在循環時爲總體構建case語句,然後添加它。