循环遍历Oracle中的行和列

Posted

技术标签:

【中文标题】循环遍历Oracle中的行和列【英文标题】:Looping through rows and then columns in Oracle 【发布时间】:2014-07-28 17:55:54 【问题描述】:

我有一个看起来像这样的表:

__________________________________________________________________________________
|id   |code  |code_status |code_due_date|code2  |code_status2 |code_due_date2|...|
|1    |ABCD  |A           |MMDDYYYY     |Null   |Null         |Null          |...|
|2    |Null  |Null        |Null         |Null   |Null         |Null          |...|
|3    |EFGH  |A           |MMDDYYYY     |ABCD   |B            |MMDDYYYY      |...|
|...  |...   |...         |...          |...    |...          |...           |...|
----------------------------------------------------------------------------------

实际的表结构是:

CREATE TABLE MY_DATA (
    PRSN_UNIV_ID                            VARCHAR2(11),
    CHKL_ITM_CD_1                           VARCHAR2(6),
    CHKL_ITM_CD_2                           VARCHAR2(6),
    CHKL_ITM_CD_3                           VARCHAR2(6),
    CHKL_ITM_CD_4                           VARCHAR2(6),
    CHKL_ITM_CD_5                           VARCHAR2(6),
    CHKL_ITM_CD_6                           VARCHAR2(6),
    CHKL_ITM_CD_7                           VARCHAR2(6),
    CHKL_ITM_CD_8                           VARCHAR2(6),
    CHKL_ITM_CD_9                           VARCHAR2(6),
    CHKL_ITM_CD_10                          VARCHAR2(6),
    CHKL_ITM_CD_11                          VARCHAR2(6),
    CHKL_ITM_CD_12                          VARCHAR2(6),
    CHKL_ITM_CD_13                          VARCHAR2(6),
    CHKL_ITM_CD_14                          VARCHAR2(6),
    CHKL_ITM_CD_15                          VARCHAR2(6),
    CHKL_ITM_CD_16                          VARCHAR2(6),
    CHKL_ITM_CD_17                          VARCHAR2(6),
    CHKL_ITM_CD_18                          VARCHAR2(6),
    CHKL_ITM_CD_19                          VARCHAR2(6),
    CHKL_ITM_CD_20                          VARCHAR2(6),
    CHKL_ITM_CD_21                          VARCHAR2(6),
    CHKL_ITM_CD_22                          VARCHAR2(6),
    CHKL_ITM_CD_23                          VARCHAR2(6),
    CHKL_ITM_CD_24                          VARCHAR2(6),
    CHKL_ITM_CD_25                          VARCHAR2(6),
    CHKL_ITM_CD_26                          VARCHAR2(6),
    CHKL_ITM_CD_27                          VARCHAR2(6),
    CHKL_ITM_CD_28                          VARCHAR2(6),
    CHKL_ITM_CD_29                          VARCHAR2(6),
    CHKL_ITM_CD_30                          VARCHAR2(6),
    CHKL_ITM_STAT_CD_1                      VARCHAR2(1),
    CHKL_ITM_STAT_CD_2                      VARCHAR2(1),
    CHKL_ITM_STAT_CD_3                      VARCHAR2(1),
    CHKL_ITM_STAT_CD_4                      VARCHAR2(1),
    CHKL_ITM_STAT_CD_5                      VARCHAR2(1),
    CHKL_ITM_STAT_CD_6                      VARCHAR2(1),
    CHKL_ITM_STAT_CD_7                      VARCHAR2(1),
    CHKL_ITM_STAT_CD_8                      VARCHAR2(1),
    CHKL_ITM_STAT_CD_9                      VARCHAR2(1),
    CHKL_ITM_STAT_CD_10                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_11                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_12                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_13                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_14                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_15                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_16                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_17                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_18                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_19                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_20                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_21                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_22                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_23                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_24                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_25                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_26                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_27                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_28                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_29                     VARCHAR2(1),
    CHKL_ITM_STAT_CD_30                     VARCHAR2(1),
    CHKL_ITM_DUE_DT_1                       DATE,
    CHKL_ITM_DUE_DT_2                       DATE,
    CHKL_ITM_DUE_DT_3                       DATE,
    CHKL_ITM_DUE_DT_4                       DATE,
    CHKL_ITM_DUE_DT_5                       DATE,
    CHKL_ITM_DUE_DT_6                       DATE,
    CHKL_ITM_DUE_DT_7                       DATE,
    CHKL_ITM_DUE_DT_8                       DATE,
    CHKL_ITM_DUE_DT_9                       DATE,
    CHKL_ITM_DUE_DT_10                      DATE,   
    CHKL_ITM_DUE_DT_11                      DATE,
    CHKL_ITM_DUE_DT_12                      DATE,
    CHKL_ITM_DUE_DT_13                      DATE,
    CHKL_ITM_DUE_DT_14                      DATE,
    CHKL_ITM_DUE_DT_15                      DATE,   
    CHKL_ITM_DUE_DT_16                      DATE,
    CHKL_ITM_DUE_DT_17                      DATE,
    CHKL_ITM_DUE_DT_18                      DATE,
    CHKL_ITM_DUE_DT_19                      DATE,
    CHKL_ITM_DUE_DT_20                      DATE,   
    CHKL_ITM_DUE_DT_21                      DATE,
    CHKL_ITM_DUE_DT_22                      DATE,
    CHKL_ITM_DUE_DT_23                      DATE,
    CHKL_ITM_DUE_DT_24                      DATE,
    CHKL_ITM_DUE_DT_25                      DATE,   
    CHKL_ITM_DUE_DT_26                      DATE,
    CHKL_ITM_DUE_DT_27                      DATE,
    CHKL_ITM_DUE_DT_28                      DATE,
    CHKL_ITM_DUE_DT_29                      DATE,
    CHKL_ITM_DUE_DT_30                      DATE   
    )

我需要做一些类似于以下伪代码的事情,但我不知道如何编写它,甚至不知道它是否可能。我需要首先遍历每一行并测试该行中的列是否等于代码。如果是,我想获取相同数字的状态和到期日期并将其放入正确的变量中。我需要循环测试大约 30 种不同的代码。

Declare variables
    variable_code_status
    variable_code_due_date
    variable_code_status2
    variable_code_due_date2
    variable_code_status3
    variable_code_due_date3

    ...

for each row
    for each column
        if column = code
            set variable_code_status = code_status
            set variable_code_due_date = code_due_date
        end if
        if column = code2
            set variable_code_status = code_status2
            set variable_code_due_date = code_due_date2
        end if
        if column - code3
            set variable_code_status = code_status3
            set variable_code_due_date = code_due_date3
        end if

        ...
    end for
end for

insert into table(
    variable_code_status
    variable_code_due_date
    variable_code_status2
    variable_code_due_date2
    variable_code_status3
    variable_code_due_date3

    ...);

我不确定这是否对任何人都有意义。

【问题讨论】:

这毫无意义...你能发布你的 actual 表结构吗?您提供的表格有重复的列名... 一个表不能有多个同名的列。您不能拥有一个包含多个名为 codecode_due_date 的列的表。 我的错。我已经解决了这个问题并添加了实际的结构。 【参考方案1】:

你可以这样做:

declare
   id MY_DATA.PRSN_UNIV_ID%type;
   cd varchar2(6);
   stat varchar2(1);
   due date;
   cur sys_refcursor;
begin
   for i in 1..30 loop
      open cur for 
      'select PRSN_UNIV_ID, CHKL_ITM_CD_'||i||', CHKL_ITM_STAT_CD_'||i||', CHKL_ITM_DUE_DT_'||i||' from MY_DATA';
      loop
         fetch cur into id, cd, stat, due;
         exit when cur%notfound;
         if .... then --> put here all your conditions
            insert into ....
         end if;
      end loop; 
   end loop;
end;

【讨论】:

【参考方案2】:

我不确定我是否完全按照您的要求进行操作,但似乎与其循环遍历,不如将UNPIVOTJOIN 用于包含您的代码的表格:

WITH cte AS (
            SELECT *
            FROM  Table1 
            UNPIVOT (value FOR field IN ("code", "code_status", "code_due_date", "code2", "code_status2","code_due_date2"))
           )
SELECT a.*
FROM cte a
INNER JOIN codes b
 ON a.value = b."code_value"

演示:SQL Fiddle

这将为您获取与您的条件相匹配的 ID、字段和值。如果您需要基表中的其他信息,可以使用这些结果重新加入。

【讨论】:

【参考方案3】:

您可以使用SYS_REFCURSORDBMS_SQL 包来动态解决此要求。以下过程是如何与查询动态交互的通用示例,在这种情况下,它只是将结果打印到控制台。您可以对其进行修改以在每次迭代时测试列描述并执行一些不同的操作。 (这适用于 11.2.0.3.0)

  PROCEDURE Output_Any_Query (
    pcRefCursor                 IN OUT SYS_REFCURSOR
  ) IS

    vnCursorNum         NUMBER;
    vnColCount          NUMBER;
    vtabDescriptions    DBMS_SQL.DESC_TAB;
    vsColumnValue       VARCHAR2(4000);

  BEGIN

    vnCursorNum := DBMS_SQL.to_cursor_number(pcRefCursor);      

    DBMS_SQL.DESCRIBE_COLUMNS(vnCursorNum, vnColCount, vtabDescriptions);

    --Print the column headers
    FOR i IN 1..vnColCount LOOP
      dbms_sql.define_column(vnCursorNum, i, vsColumnValue, 4000);
      dbms_output.put(RPAD(LPAD(vtabDescriptions(i).col_name,15),20)||'|');
    END LOOP;

    --End of line
    dbms_output.put_line('');

    --loop through the rows
    WHILE ( dbms_sql.fetch_rows(vnCursorNum) > 0 ) LOOP 

      --loop across the columns
      FOR i IN 1 .. vnColCount LOOP 
        dbms_sql.column_value(vnCursorNum, i, vsColumnValue);
        dbms_output.put(RPAD(NVL(vsColumnValue,' '),20)||'|');
      END LOOP;

      --End of line   
      dbms_output.put_line('');

    END LOOP;

  END;

【讨论】:

以上是关于循环遍历Oracle中的行和列的主要内容,如果未能解决你的问题,请参考以下文章

遍历Excle工作薄的行和列,文本抽取

急求!VB编程问题:有一个n×m的矩阵,编写程序,找出其中最大的元素所在的行和列,并输出其值及行号和列

js 遍历行和列

具有多维数组java的行和列

Pandas.DataFrame 的 iterrows()方法详解

Oracle 10g 从两个不同的行和列聚合成一行