2016-03-05 53 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'*/