1

plsql コードに問題があり、ほとんどすべてを試しています。今、私は自分の問題を解決するための心と力を失っています:)

すべてのテーブル スキーマで変数 v_ss に割り当てられた特定の文字列を検索し、それを DBMS_OUTPUT に出力したい場合があります。そのような場合の既製のソリューションがあることは知っていますが、自分でコーディングしたかったのです。以下のコードでは、v_stmt に「テーブルが存在しません」というエラーが表示されます。この select は rec.column_name を認識しないと思いますが、なぜですか?

これが私のコードです:

DECLARE
 v_stmt VARCHAR2(1000);
 v_ss VARCHAR2(30) := 'Argentina';

 v_own ALL_TAB_COLUMNS.OWNER%TYPE;
 v_tab_nam ALL_TAB_COLUMNS.TABLE_NAME%TYPE;
 v_col_nam ALL_TAB_COLUMNS.COLUMN_NAME%TYPE;

 CURSOR cur_asc IS
   SELECT t.owner, t.table_name, t.column_name
   FROM SYS.ALL_TAB_COLUMNS t
   WHERE t.OWNER LIKE 'HR'
     AND t.DATA_TYPE LIKE 'VARCHAR2';


BEGIN
  FOR rec IN cur_asc LOOP
    v_stmt := 'SELECT rec.owner, rec.table_name, rec.column_name FROM rec.table_name WHERE rec.column_name LIKE :1';
    EXECUTE IMMEDIATE v_stmt INTO v_own, v_tab_nam, v_col_nam USING v_ss;
    DBMS_OUTPUT.put_line(v_own || ':' || v_tab_nam || ':' || v_col_nam);
  END LOOP;


END;
/

Error report -
ORA-00942: table or view does not exist
ORA-06512: at line 19
00942. 00000 -  "table or view does not exist"
*Cause:    
*Action:

バグの説明と修正方法を教えてください。前もって感謝します

4

3 に答える 3

1

ここには 2 つの問題があります。

  1. 'SELECT rec.owner...' はownerエイリアスを持つテーブルから呼び出された列を選択しようとしているため、テーブルと列の名前を動的 SQL に連結する必要がありrecます。これは for ループ レコードを参照しません。
  2. テーブル内に一致する行がないか、一致する行が多数ある可能性があるためselect into、 を使用できません。カーソルを使用する必要があります。

これを試して:

DECLARE
 v_stmt VARCHAR2(1000);
 v_ss VARCHAR2(30) := 'Argentina';

 v_own ALL_TAB_COLUMNS.OWNER%TYPE;
 v_tab_nam ALL_TAB_COLUMNS.TABLE_NAME%TYPE;
 v_col_nam ALL_TAB_COLUMNS.COLUMN_NAME%TYPE;

 CURSOR cur_asc IS
   SELECT t.owner, t.table_name, t.column_name
   FROM ALL_TAB_COLUMNS t
   WHERE t.DATA_TYPE LIKE 'VARCHAR2'
   AND ROWNUM < 10;

 c SYS_REFCURSOR;

BEGIN
  FOR rec IN cur_asc LOOP
    v_stmt := 'SELECT ''' || rec.owner || ''',''' || rec.table_name || ''', ''' || rec.column_name || ''' FROM ' || rec.table_name || ' WHERE ' || rec.column_name || ' LIKE :1';
    OPEN c FOR v_stmt USING v_ss;
    LOOP
      FETCH c INTO v_own, v_tab_nam, v_col_nam;
      EXIT WHEN c%NOTFOUND;
      DBMS_OUTPUT.put_line(v_own || ':' || v_tab_nam || ':' || v_col_nam);
    END LOOP;
    CLOSE c;
  END LOOP;
END;
/
于 2016-02-19T11:13:29.317 に答える
1

v_stmt := 'SELECT rec.owner, rec.table_name, rec.column_name FROM rec.table_name WHERE rec.column_name LIKE :1';

  1. 動的 SQL ステートメントの形式が正しくありません。変数を単一引用符で囲むと、それらは変数ではなくリテラルとして扱われます。
  2. table_name の前にスキーマのプレフィックスを付ける必要があります。それ以外の場合は、ユーザーとして接続しているときにスクリプトを実行する必要がありHRます。
v_stmt := 'SELECT '''||rec.owner||''', '''|| rec.table_name||''','
                     ||rec.column_name||' FROM '||rec.owner||'.'.
                     ||rec.table_name||' WHERE '||rec.column_name||' のように:1';

動的ステートメントを使用する場合は常に、常にDBMS_OUTPUTを使用して、生成されている実際の SQL を最初に確認してください。これは、動的クエリをデバッグする最良の方法です。

  1. NO_DATA_FOUND使用しているフィルターに一致しないすべてのテーブルに対してエラーがスローされるため、例外を処理する必要があります。
SQL>宣言
  2 v_stmt VARCHAR2(1000);
  3 v_ss VARCHAR2(30) := 'アルゼンチン';
  4 v_own ALL_TAB_COLUMNS.OWNER%TYPE;
  5 v_tab_nam ALL_TAB_COLUMNS.TABLE_NAME%TYPE;
  6 v_col_nam ALL_TAB_COLUMNS.COLUMN_NAME%TYPE;
  7 CURSOR cur_asc
  8IS
  9 SELECT 所有者、
 10 t.table_name、
 11 t.column_name
 12 FROM SYS.ALL_TAB_COLUMNSt
 13 WHERE t.OWNER LIKE 'HR'
 14 AND t.DATA_TYPE LIKE 'VARCHAR2';
 15 開始
 16 FOR rec IN cur_asc
 17 ループ
 18 v_stmt := 'SELECT '''||rec.owner||''', '''|| rec.table_name||''','
 19 || rec.column_name||' FROM '||rec.owner||'.'.
 20 || rec.table_name||' WHERE '||rec.column_name||' のように:1';
 21 開始
 22 EXECUTE IMMEDIATE v_stmt INTO v_own、
 23 v_tab_nam、
 24 v_col_nam USING v_ss;
 25 DBMS_OUTPUT.put_line(v_own || ':' || v_tab_nam || ':' || v_col_nam);
 26 例外
 27 いつ NO_DATA_FOUND THEN
 28ヌル;
 29 エンド;
 30 エンドループ;
 31エンド;
 32 /
HR:国:アルゼンチン

PL/SQL プロシージャが正常に完了しました。
于 2016-02-19T11:19:27.487 に答える