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

除非您有使用动态 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 回答
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 回答