2016-03-05 52 views
2

現在我有一個這樣的表。使用for循環通過PL/SQL中的名稱選擇不同的列

 
Table name: itemlist 

Item year value1 value2 value3 value4 value5 ... value99 
-------------------------------------- 
foo1 12 32 48 
foo2 13 32 50 
foo3 14 32 50 
foo4 15 33 48 
foo5 16 33 48 
foo6 17 33 48 
foo7 13 38 42 
foo8 14 34 44 
foo9 15 36 46 
foo10 16 37 48 

這裏的任務,我想找出爲每個值(例如值1,值等),有多少項目是高於35,有多少是低於35

是有一種方法循環的過程,所以我不必從每個值列中選擇所有的東西。

這是選擇其中一列的示例。

SELECT count(value1) as v1_number 
FROM itemlist 
WHERE v1_number > 35 
UNION 
SELECT v1_number 
FROM itemlist 
WHERE v1_number <35; 

這樣的工作,但我必須輸入99次。

所以我的解決方案將是PL/SQL中的for循環。它看起來像這樣:

BEGIN 
FOR i in 1..99 LOOP 
SELECT count(value || i) as v_number || i 
FROM itemlist 
WHERE v_number || i > 35 
END LOOP 

顯然,這是行不通的,問題是我不知道如何與指數1-99串聯值。

+0

這是你當你非規範化的數據有問題。如果您每項,每年和每一行都有一行,那麼查詢就會很簡單。 –

+0

@eli,有沒有任何答案可以幫助你?你可以評論或接受嗎? – trincot

回答

0
SELECT COUNT(CASE WHEN Value1 > 35 THEN 1 END) AS v1_number, 
     COUNT(CASE WHEN Value2 > 35 THEN 1 END) AS v2_number, 
     COUNT(CASE WHEN Value3 > 35 THEN 1 END) AS v3_number, 
     -- ... 
     COUNT(CASE WHEN Value99 > 35 THEN 1 END) AS v99_number 
FROM itemlist; 

然後,你可以做複製/粘貼和查找/替換變化><得到下面的值。

或者你可以使用PL/SQL動態生成查詢:

SET SERVEROUTPUT ON; 
VARIABLE cur REFCURSOR; 

DECLARE 
    qry CLOB := EMPTY_CLOB(); 
    line_above VARCHAR2(4000); 
    line_below VARCHAR2(4000); 
BEGIN 
    FOR i IN 1 .. 99 LOOP 
    line_above := ', COUNT(CASE WHEN Value' || i || ' > 35 THEN 1 END) AS v' || i || '_above_number'; 
    line_below := ', COUNT(CASE WHEN Value' || i || ' < 35 THEN 1 END) AS v' || i || '_below_number'; 
    qry := qry || line_above || line_below; 
    END LOOP; 
    qry := 'SELECT' || SUBSTR(qry, 2) || ' FROM itemlist'; 
    DBMS_OUTPUT.PUT_LINE(qry); 
    OPEN :cur FOR qry; 
END; 
/

PRINT :cur; 
1

使用UNPIVOT syntax 創建視圖。這是一次性努力。然後,在該視圖上執行查詢將更容易。

所以首先創建視圖(延長所有值列):

CREATE VIEW v_itemlist AS 
    SELECT * 
    FROM unpivot_test 
    UNPIVOT (value FOR value_id IN (
       value1 AS 1, 
       value2 AS 2, 
       value3 AS 3, 
       ... 
       value98 AS 98, 
       value99 AS 99 
      )); 

然後你就可以像查詢:

SELECT item, year, 
     SUM(CASE value > 35 THEN 1 END) AS above_35, 
     SUM(CASE value < 35 THEN 1 END) AS below_35, 
FROM  v_itemlist 
GROUP BY item, year; 

一旦你習慣使用的視圖,你可以考慮以normalised的方式創建基表,這樣您就可以從索引中受益,並且可以輕鬆地分別插入和刪除值,對它們進行排序,檢測重複項等。這就是關係數據庫如何建模並給出最佳結果值。

0

我upvoted trincot的答案,但也許你正在尋找的東西更多類似這樣的

create or replace function eval(tab in varchar2, col in varchar2, cond in varchar2) return number as 
    ret number; 
begin 
    execute immediate 'select count(*) from '||tab||' where '||col||cond into ret; 
    return ret; 
end; 

select table_name, column_name, 
eval(table_name, column_name, '>35'), eval(table_name, column_name, '<35') 
from all_tab_columns 
where table_name = upper('itemlist') and column_name like 'value%' /*and data_type = 'NUMBER'*/ 
相關問題