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
如何解决此错误?
答案 0 :(得分: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注入攻击的可能性之外,还可以避免转义本地变量中的数据,并且无需为字符串添加额外的引号。
答案 1 :(得分: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。
N.B。注意不要将此过程公开,因为它易受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;