2017-02-01 3 views
2

私は頻繁にデータベース&のユーザーではありません。いくつかのPL/SQLブロックを作成/実行/実行する必要があります。私は、Oracleデータベース・ユーザーにSYSDBAとしてSYSとして実行中に以下のブロックを有する場合、エラーをスローし、今同様の状況がある: -行1のエラー:ORA-00911:無効な文字ORA-06512:行17

DECLARE 
* 
ERROR at line 1: 
ORA-00911: invalid character 
ORA-06512: at line 17 

PL/SQLブロックは以下の通りであります: -

DECLARE 
TYPE RefCurTyp IS REF CURSOR; 
alter_tbl VARCHAR2(200); 
a_null CHAR(1); 
tbl VARCHAR2(200); 
clmn VARCHAR2(200); 
dtyp VARCHAR2(200) ; 
dlth VARCHAR2(200); 
c RefCurTyp; 
BEGIN 
open c for 'select utc.table_name, utc.column_name, utc.data_type, utc.data_length FROM user_tab_columns utc, user_tables ut 
WHERE utc.data_type = ''VARCHAR2'' AND utc.char_used =''B'' AND ut.table_name = utc.table_name'; 
LOOP 
dbms_output.put_line(clmn); 
FETCH c INTO tbl, clmn, dtyp, dlth; 
EXIT WHEN c%NOTFOUND; 
EXECUTE IMMEDIATE 
'alter table '||tbl||' modify ('||clmn||' '||dtyp||'('||dlth||' CHAR))'; 
END LOOP; 
CLOSE c; 
END; 

も、私はこれで問題を把握することができません3日間それを私の頭を叩きました。すべての入力をいただければ幸いです。

私が手にヒキガエルを経由して同じコードを実行している間: - enter image description here

+1

動的SQLでエラーが発生した場合、実行しようとしているものを正確に表示するために 'dbms_output()'コールを追加すると便利です。あなたはおそらく少なくとも出力のテーブル名を取得しているはずです(もちろん、serveroutputを設定している場合)ので、どのテーブルが既に失敗しているかを知ることができます。それについて何が違うのですか?私はそれが奇妙な何かを含む引用符で囲まれた識別子を持つ列を持っていると推測しますが、推測しかできません。実際に生成されたalterコマンドを表示すると、それが明白になるはずです。 –

+1

また、なぜSYSが所有するテーブルを変更していますか?それは良いアイデアのようには思えません。 –

+0

dlthは長さです...タイプを 'modify varchar2(10 CHAR)'に変更しようとしました...私には構文が正しくないように見えますが、動的SQLは 'modify A varchar2(10)'のようにすべきです。 – are

答えて

3

をあなたが実行している動的ステートメントを表示するためにdbms_outputを使用することができます。同じことを確認して実行するには、ステートメントを変数に入れておく方が簡単です(使用していないステートメントを使用しています)。カーソル変数を必要としないカーソルタイプを変更した場合は、カーソルクエリの一部としてステートメントを構築し、それを複数回参照することができます。また、あなたの単一引用符をエスケープする必要はありません。

set serveroutput on 

BEGIN 
    FOR r IN (
    SELECT 'alter table ' || utc.table_name || ' modify (' || utc.column_name || ' ' 
     || utc.data_type || '(' || utc.data_length || ' CHAR))' as alter_stmt 
    FROM user_tab_columns utc 
    JOIN user_tables ut ON ut.table_name = utc.table_name 
    WHERE utc.data_type = 'VARCHAR2' AND utc.char_used ='B' 
) 
    LOOP 
    dbms_output.put_line(r.alter_stmt); 
    execute immediate r.alter_stmt; 
    END LOOP; 
END; 
/

私はあなたが無効な文字が含まれており、引用識別子を使用して作成されたテーブルやカラム名を持っている疑いがあります。それは恐らく失敗する直前の出力から明らかでしょう。あなたは簡単に文の生成の一部としてそれらを連結することで、識別子のすべてに二重引用符を追加することができます。

BEGIN 
    FOR r IN (
    SELECT 'alter table "' || utc.table_name || '" modify ("' || utc.column_name || '" ' 
     || utc.data_type || '(' || utc.data_length || ' CHAR))' as alter_stmt 
    FROM user_tab_columns utc 
    JOIN user_tables ut ON ut.table_name = utc.table_name 
    WHERE utc.data_type = 'VARCHAR2' AND utc.char_used ='B' 
) 
    LOOP 
    dbms_output.put_line(r.alter_stmt); 
    execute immediate r.alter_stmt; 
    END LOOP; 
END; 
/

あなたがSYSとして接続しながらこれを実行している、とあなたはuser_tablesを見ていると述べました、あなたはSYSが所有するテーブルを変更しています - これは非常に悪い考えです。組み込みのデータ・ディクショナリ表を変更するつもりがない場合でも、そうすることになります。これは、SYSスキーマに独自のオブジェクトを作成していることを意味します。これは一般的には非常に悪い考えです。別のユーザーアカウントを作成し、そのスキーマ内のオブジェクトの作成と変更のみを行う必要があります。なぜならアンダースコアORA-00911になるだろう

alter table _default_auditing_options_ modify (A VARCHAR2(1 CHAR)); 

...:私の11グラムインスタンスSYSで

はと私の最初のクエリからの出力を生成し、テーブルを持っています。

alter table "_default_auditing_options_" modify ("A" VARCHAR2(1 CHAR)); 

を...しかし、再び、あなたはビルトインテーブルを変更しないで必要があります。識別子が引用される場合、それは動作します。

+0

大きな+1は 'これを行うことはありませんim SYSスキーマ'です。私は地平線で死んだデータベースを見る。 – BriteSponge

+0

ありがとう、アレックス、それは非常に参考になった..私は別のユーザーとして試してSYSを避ける​​。 – N29

関連する問題