2017-03-20 3 views
0

私は2つのカーソルc11とc2を持っています。私は2つのテーブルcompare1とcompare2を持っています。私はc1の結果をc2のカーソルに渡したい。 user_tab_columnsからテーブルのカラム名を取得しています。私は列名を渡して、compare1とcompare2のテーブルの間で一意のレコードの違いを取得したい。しかし、c1の列名はc2に渡されません。私が試したコードを見つけてください。あなたに最初のカーソルから列名を渡しているので、事前にc1.Thanksに値を渡すことであるカーソルから別のカーソルのステートメントを選択するために列名を渡す

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; 

ヘルプ私は

+0

これはどのRDBMSですか? MySQL、PostgreSQL、Oracle、SQL Server、IBM DB2などを使用しているかどうかにかかわらず、多くの場合違いがあります。あなたの質問に関連タグを追加してください! –

+0

私たちはOracleを使用しています – mano

答えて

2

あなたはそれが期待するようにコードが動作していない主な理由であります2番目のカーソルをリテラル値として返します。

したがって、2番目のカーソルでマイナスを実行すると、1つの文字列がその文字列と同じかどうかが比較されます。つまり、返される行はありません。私。これを回避するには

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

、あなたは動的SQLを使用する必要があります - ここにカーソルとrefカーソルを使用した例です:それは本質的である

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; 
/

あなたは、私が変換されてきたことがわかります各行を明示的にフェッチするのではなく、最初のカーソルをループのためのカーソルに丸めます。そうすれば、行の終わりに達したことを確認したり、カーソルを閉じるのを心配する必要はありません。 2番目のカーソルを通る内部ループは、紛失したexit when rc%notfound節に追加しました。

マイナスクエリからdistinctを削除しました。つまり、minusは既に明示的に行を区別しているため、明示的に指定する必要はありません。

ただし、行単位の挿入がありますが、これは最善の方法ではありません。すべての作業を1つのinsert文で行う必要があります。 :

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; 
/

NBテストされていない。

+0

お返事ありがとう:)。今私はポイントを持っている..しかし、私は識別子が長すぎるselectステートメントのエラーです。それを取り除く方法はありますか? – mano

+0

お詫び申し上げます。私は最終的なpl/sqlブロックから '即実行'を逃してしまいました。エラーメッセージについては、列のエイリアシングが役立つことがあります。 || CHR(10)|| '' SELECT '' B001 '' some_alias_name '' || CHR(10)|| – Boneist

+0

最初の解決策として、エイリアス名を使用しようとすると、 'expected USing'というエラーが表示されます – mano

関連する問題