0
CREATE TABLE TEST_CASE
  (
    ID NUMBER(19,2),
    CURRENCY_TYPE VARCHAR2(30),
    PAIDAMT NUMBER(19,2),
    RECVDAMT NUMBER(19,2),
    AMTDUE NUMBER,
    TRANSACTION_DATE VARCHAR2(30)
  );

名前にAMTが含まれるフィールドをフェッチするプロシージャを作成しました。しかし、手順は実行中にエラーを示しています。なぜこのエラーが発生するのか理解できません。

create or replace procedure chk_amt
(
    vtbl varchar2
)
as
tblcursor sys_refcursor;
tblsqlstr varchar2(1000);
importedrows VARCHAR2(1000); 
BEGIN
    tblsqlstr := 'Select COLUMN_NAME from user_tab_columns where table_name= '|| vtbl ||' and COLUMN_NAME like upper(''%AMT%'')' ;   
    OPEN tblcursor for tblsqlstr;
loop
fetch tblcursor into importedrows;
DBMS_OUTPUT.PUT_LINE(importedrows); 
EXIT WHEN tblcursor%NOTFOUND;
end loop;
CLOSE tblcursor;
end;
/

エラーは

ORA-00904: "TEST_CASE": invalid identifier
ORA-06512: at "***.CHK_AMT", line 11
ORA-06512: at line 2

このエラーを解決するにはどうすればよいですか?

4

2 に答える 2

2

vtblを一重引用符で囲んで動的ステートメントに追加すると、次のようになります:-

tblsqlstr := 'Select COLUMN_NAME from user_tab_columns where table_name= '''|| vtbl ||''' and COLUMN_NAME like upper(''%AMT%'')' ;  

これは、コードが実行されるときに、vtblの値がtable_aの場合、実際に実行されるステートメントはtable_aではなく'table_a'になることを意味します。

注意:このプロシージャはSQLインジェクションに対して脆弱であるため、公開しないように注意してください。理想的には、代わりにバインド変数を使用する必要があります。以下の例:-

CREATE OR REPLACE PROCEDURE chk_amt(vtbl VARCHAR2) AS
tblcursor    SYS_REFCURSOR;
tblsqlstr    VARCHAR2(1000);
importedrows VARCHAR2(1000);
BEGIN
tblsqlstr := 'Select COLUMN_NAME from user_tab_columns where table_name= :val_bnd and COLUMN_NAME like upper(''%AMT%'')';
OPEN tblcursor FOR tblsqlstr USING vtbl;
LOOP
    FETCH tblcursor
        INTO importedrows;
    dbms_output.put_line(importedrows);
    EXIT WHEN tblcursor%NOTFOUND;
END LOOP;
CLOSE tblcursor;
END;
于 2012-10-09T14:37:25.190 に答える
2

動的 SQL を使用する特別な理由がない限り、静的 SQL を使用する方がはるかに簡単です。また、明示カーソルが有利であるという何らかの理由がない限り、通常は暗黙カーソルを使用する方が簡単です。コード スニペットは動的 SQL または明示カーソルを使用する必要性を示していないため、次のように簡略化できます。

create or replace procedure chk_amt
(
    vtbl varchar2
)
as
BEGIN
  FOR columns IN (SELECT column_name
                    FROM user_tab_columns
                   WHERE table_name = vtbl
                     AND column_name LIKE '%AMT%')
  LOOP
    DBMS_OUTPUT.PUT_LINE(columns.column_name);
  END LOOP; 
end;

取得している特定のエラーは、vtbl変数を動的 SQL ステートメントに連結した結果です。このように文字列を連結する場合は、文字列内の変数の前後に一重引用符を配置する必要があり、テーブル名の単一引用符をエスケープする必要があります (もちろん、テーブル名の一重引用符)。動的 SQL を使用する必要がある場合は、代わりにバインド変数を使用する方がはるかに優れています。

tblsqlstr := 'Select COLUMN_NAME 
                from user_tab_columns 
                where table_name= :1 
                  and COLUMN_NAME like upper(''%AMT%'')' ;   
OPEN tblcursor for tblsqlstr using vtbl;

より効率的になり、SQL インジェクション攻撃の可能性を回避することに加えて、ローカル変数のデータをエスケープする必要がなくなり、文字列に余分な引用符を追加する必要がなくなります。

于 2012-10-09T14:29:01.803 に答える