1

PL/SQLの学習を始めたばかりです。stackoverflow の投稿に続いて、以下のように Oracle で特定の値を検索するスクリプトを作成しました。

DECLARE
  match_count INTEGER;
  v_owner VARCHAR2(255);
  v_search_value NUMBER;
BEGIN
  v_owner:='USERA USERB';
  v_search_value:=4823.0;
  EXECUTE IMMEDIATE
  'INSERT INTO TMP SELECT owner, table_name, column_name FROM all_tab_cols WHERE instr(:1, owner)>0 AND data_type like ''%NUMBER%''' USING v_owner;
  commit;
  FOR t IN (SELECT owner, table_name, column_name FROM TMP) LOOP
    EXECUTE IMMEDIATE 
    'SELECT COUNT(*) FROM '||t.owner||'.'||t.table_name||' WHERE '||t.column_name||'= :1'
    INTO match_count
    USING v_search_value;
    IF match_count > 0 THEN
      EXECUTE IMMEDIATE
      'INSERT INTO RESULT VALUES(:1, :2, :3, :4)'
      USING t.owner, t.table_name, t.column_name, match_count;
      commit;
    END IF;
  END LOOP;
END;

スクリプトを実行する前に、テーブル TMP と RESULT が適切に作成されています。しかし、スクリプトを実行すると、12 行目に「connect by 句が必要です」という ORA-01788 エラーが表示されます。コードが原因でこのエラーが発生する理由と、スクリプトが適切に実行されるように変更する方法を知りたいです。ありがとう!

4

1 に答える 1

6

おそらく、予約語levelである (私が見ていない間にフローリンが示唆したように)という列を持つテーブルがあるでしょう。

いずれにせよ - だけlevelでなくLEVEL, またはLevel- そうすることができるかどうかを確認するには:

select owner, table_name, column_name
from all_tab_columns
where upper(column_name) = 'LEVEL';

または、使用されている予約語を探します (ただし、潜在的な問題がすべて見つかるとは限りません)。

select atc.owner, atc.table_name, atc.column_name, vrw.keyword
from all_tab_columns atc
join v$reserved_words vrw on vrw.keyword = upper(atc.column_name);

同様のクエリを実行して、他の場所で潜在的な問題を見つけることができall_tablesますall_objects

TMPテーブルを気にしないクエリの修正版を実行すると、なぜそれが必要なのかわかりません。挿入に動的 SQL を使用しません。コミットしません (これはブロック内で行うのは奇妙なことです - いずれにせよ、挿入するたびに行う必要はありません)。resultsそして、私の利益のために、テーブルを作成する必要はなく、一致を表示するだけです:

declare
  match_count integer;
  v_owner varchar2(255);
  v_search_value number;
begin
  v_owner := 'USERA USERB';
  v_search_value := 4823.0;
  for t in (
      select owner, table_name, column_name
      from all_tab_cols
      where instr(v_owner, owner) > 0
      and data_type like '%NUMBER%'
    ) loop
    execute immediate 
      'select count(*) from ' || t.owner ||'.'|| t.table_name
        || ' where ' || t.column_name || ' = :1'
      into match_count using v_search_value;
    if match_count > 0 then
--    insert into results values (t.owner, t.table_name,
--      t.column_name, match_count);
      dbms_output.put_line('Matched ' || t.owner ||'.'|| t.table_name
        ||'.'|| t.column_name ||': '|| match_count);
    end if;
  end loop;
end;
/

...これで正常に完了します。level列のあるテーブルを追加すると:

create table t42 ("LEVEL" number);

...そして同じブロックをもう一度実行すると、次のようにもなります:

ORA-01788: CONNECT BY clause required in this query block
ORA-06512: at line 14
01788. 00000 -  "CONNECT BY clause required in this query block"
*Cause:    
*Action:

オブジェクト名に予約語を使用しないようにする以外に、すべてのオブジェクト名を二重引用符で囲むことでこれを機能させることができます。

    execute immediate 
      'select count(*) from "' || t.owner ||'"."'|| t.table_name
        || '" where "' || t.column_name || '" = :1'
      into match_count using v_search_value;

これにより、大文字と小文字が混在するオブジェクト名にも対処できますが、これも避ける必要があります。

于 2013-02-28T08:44:09.450 に答える