从一个游标传递列名以选择另一个游标

时间:2017-03-20 06:33:40

标签: sql oracle cursor

我有两个游标c11和c2。我有两个表compare1和compare2.Both有相同的列,但值不同。我想将c1的结果传递给c2游标。我从user_tab_columns获取表的列名。我想传递列名以获得compare 1和compare2表之间唯一记录的差异。但是c1中的列名未传递给c2。请找到我尝试过的代码。

DECLARE
   COL         VARCHAR2 (200);
  OUTRECORD   VARCHAR2 (200);
   CURSOR c1  IS
  SELECT COLUMN_NAME
    FROM all_tab_columns
   WHERE     table_name = 'COMPARE1';            
CURSOR c2( col varchar(200))   IS--col is the column names from c1 
   (SELECT DISTINCT COL
            FROM COMPARE1
          MINUS
          SELECT DISTINCT COL
            FROM COMPARE2);
BEGIN
  OPEN c1;
  LOOP
    FETCH c1 INTO COL;
    DBMS_OUTPUT.put_line (COL);
    OPEN c2(col);--col Is not passing to 2nd cursor
    LOOP
      FETCH c2 INTO OUTRECORD;--outrecord is empty is col is not passed to 2nd cursor
      INSERT INTO RESULT
          VALUES ('B001',
                  'COMPARE',
                  '2018',
                  COL,
                  OUTRECORD,--empy value
                  'NOT PRESENT IN 2017');
      COMMIT;
    END LOOP;
    CLOSE c2;
  END LOOP;
  CLOSE c1;
END;

帮我将值传递给c1.Thanks提前

1 个答案:

答案 0 :(得分:2)

您的代码无法正常工作的主要原因是您将第一个游标中的列名称作为文字值传递给第二个游标。

因此,当您在第二个游标中执行减号时,您将比较一个字符串是否与该字符串相同,这意味着不会返回任何行。即它基本上是:

select 'x' from some_table
minus
select 'x' from some_other_table;

要解决这个问题,你需要使用动态sql - 这是一个使用游标和引用游标的例子:

DECLARE
  rc        SYS_REFCURSOR;
  outrecord VARCHAR2(200);
BEGIN
  FOR r1 IN (SELECT column_name col
             FROM   all_tab_columns
             WHERE  table_name = 'COMPARE1')
  LOOP
    dbms_output.put_line(r1.col);

    OPEN rc FOR 'SELECT '||r1.col||' col'||CHR(10)||
                'FROM   compare1'||CHR(10)||
                'MINUS'||CHR(10)||
                'SELECT '||r1.col||' col'||CHR(10)||
                'FROM   compare2';

    LOOP
      FETCH rc
        INTO outrecord; 

      EXIT WHEN rc%NOTFOUND;

      INSERT INTO RESULT -- you should list the columns being inserted into here
      VALUES
        ('B001',
         'COMPARE',
         '2018',
         r1.col,
         outrecord,
         'NOT PRESENT IN 2017');
      COMMIT;
    END LOOP;
  END LOOP;

  CLOSE rc;
END;
/

你可以看到我已经将第一个游标的循环转换为了一个for-for-loop,而不是显式地获取每一行。这样,您不必担心检查是否已到达行尾或关闭光标。我通过第二个游标的内部循环添加了缺少的exit when rc%notfound子句。

另请注意,我已从您的减号查询中删除了distinct - minus已经区分了行,因此无需明确说明它。

但是,你所要做的是逐行插入,这不是最好的方法 - 你应该在一个插入语句中完成所有工作,你可以在下面看到:

BEGIN
  FOR r1 IN (SELECT column_name col
             FROM   all_tab_columns
             WHERE  table_name = 'COMPARE1')
  LOOP
    dbms_output.put_line(r1.col);

    execute immediate 'INSERT INTO RESULT'||CHR(10)|| -- you should list the columns being inserted into here
                      'SELECT ''B001'','||CHR(10)||
                      '       ''COMPARE'','||CHR(10)||
                      '       ''2018'','||CHR(10)||
                      '       '''||r1.col||''','||CHR(10)||
                      '       '||r1.col||CHR(10)||
                      'FROM   compare1'||CHR(10)||
                      'MINUS'||CHR(10)||
                      'SELECT ''B001'','||CHR(10)||
                      '       ''COMPARE'','||CHR(10)||
                      '       ''2018'','||CHR(10)||
                      '       '''||r1.col||''','||CHR(10)||
                      '       '||r1.col||CHR(10)||
                      'FROM   compare2';

  END LOOP;    END;
/

N.B。未经测试。