当我尝试 运行 我编写的 Oracle 存储过程时出现 ORA-00933: SQL 命令未正确结束错误

Getting a ORA-00933: SQL command not properly ended error when I try to run an Oracle stored procedure that I wrote

作为项目的一部分,我正在研究我们公司使用的 peoplesoft 记录和字段的数据映射。我必须记录超过 25,000 个字段,但它变得乏味,并且比我以正常方式完成时花费的时间要多得多。所以,我写了一个存储过程来减少记录翻译值的一些工作。

这是我的存储过程的代码:

CREATE OR REPLACE PROCEDURE SP_DATAMAPPINGINFO AS 
TYPE EmpCurTyp IS REF CURSOR;
newrow_cursor    EmpCurTyp;
txtable_cursor EmpCurTyp;

recname varchar2(30);
recdescr varchar2(200);
fieldnum number(3);
fieldname varchar2(30);
fieldescr varchar2(2000);
keyflag varchar2(1);
fieldtype varchar2(20);
distinctcount number(10);

query1_str varchar(300);
query2_str varchar(300);
query3_str varchar(300);

fieldvalue varchar2(200);
hyphen varchar2(5);
txvalue varchar2(200);
fielduse varchar2(500);

tablename varchar2(40);
intertxtabname varchar2(30);
txtablename varchar2(40);

CURSOR get_fields is
        select A.RECNAME as "Record", A.RECDESCR as "Record Description"
        , B.FIELDNUM as "FieldNum", B.FIELDNAME as "Field", C.DESCRLONG as "Field Description", CASE WHEN
        EXISTS(select K.FIELDNAME FROM PSRECFLDDBKEYVW K WHERE K.RECNAME = A.RECNAME AND K.FIELDNAME=B.FIELDNAME)
        THEN 'Y' ELSE 'N' END as "Key (Y/N)", DECODE (C.FIELDTYPE,
                 0, 'Character',
                 1, 'Long Char',
                 2, 'Number',
                 3, 'Signed Number',
                 4, 'Date',
                 5, 'Time',
                 6, 'DateTime',
                 8, 'Image/ Attachment',
                 9, 'Image Reference',
                 'Unknown') as "FieldType"
        FROM PSRECDEFN A, PSRECFIELDDB B LEFT JOIN PSDBFIELD C ON (B.FIELDNAME = C.FIELDNAME)
        WHERE B.RECNAME = A.RECNAME
        AND A.RECNAME IN (select R.RECNAME from PSRECDEFN R, DBA_TABLES T
        WHERE ('PS_'||R.RECNAME=T.TABLE_NAME)
        AND T.NUM_ROWS > 0
        AND R.RECTYPE=0)
        order by A.RECNAME, B.FIELDNUM;

BEGIN
OPEN get_fields;
    LOOP
    FETCH get_fields INTO recname, recdescr, fieldnum, fieldname, fieldescr, keyflag, fieldtype;


    fielduse := '';
    tablename := 'PS_' || recname;
    hyphen := ' - ';
    fieldvalue := '';
    txvalue := '';
    intertxtabname := '';
    txtablename := '';

    if (fieldname <> '%EMPLID%' and fieldname <> '%DESCR%' and fieldname <> '%COMMENT%') THEN
        query1_str := 'select RI.EDITTABLE FROM PSRECDEFN RD, PSRECFIELDDB RI WHERE RD.RECNAME = RI.RECNAME 
        AND RD.RECNAME = ' || recname || 'AND RI.FIELDNAME = ' || fieldname;

        OPEN txtable_cursor FOR query1_str;
            FETCH txtable_cursor INTO intertxtabname;
        CLOSE txtable_cursor;

        query2_str := 'select count(distinct T.' || fieldname || ') FROM ' || tablename;

        IF (intertxtabname IS NOT NULL) THEN
            txtablename := 'PS_' || intertxtabname;
            query3_str := 'select distinct T.' || fieldname || ', TR.DESCR FROM ' || tablename || ' T left join ' || txtablename || ' TR ON T.' 
            || fieldname || ' = TR.' || fieldname || ' order by T.' || fieldname;
        ELSE
            txtablename := '';
            query3_str := 'select distinct DT.' || fieldname || ', DTR.XLATLONGNAME FROM ' || tablename || ' DT left join PSXLATITEM DTR on 
            (DTR.FIELDNAME = ''' || fieldname || ''' and DT.' || fieldname || ' = DTR.FIELDVALE) order by DT.' || fieldname;
        END IF;

        execute immediate query2_str into distinctcount;

        if(distinctcount > 150) THEN
            fielduse := 'More than 150';
        ELSE
            OPEN newrow_cursor FOR query3_str USING 'fieldname';
                LOOP
                FETCH newrow_cursor INTO fieldvalue, txvalue;
                fielduse := fieldvalue || ' - ' || txvalue;
                EXIT WHEN newrow_cursor%NOTFOUND;
                END LOOP;
            CLOSE newrow_cursor;
        END IF;

    ELSE
        fielduse := 'SKIPPING';
    END IF;
    
    dbms_output.put_line(recname || ',' || recdescr || ',' || fieldnum || ',' || fieldname || ',' || fieldescr || ',' || keyflag || ',' || fieldtype || ',' || fielduse);
    END LOOP;
CLOSE get_fields;
    
NULL;
END SP_DATAMAPPINGINFO;

存储过程编译没有任何错误,但是当我执行它时,出现以下错误:

Error starting at line : 1 in command -

BEGIN SP_DATAMAPPINGINFO; END;

Error report -

ORA-00933: SQL command not properly ended

ORA-06512: at "SYSADM.SP_DATAMAPPINGINFO", line 69

ORA-06512: at line 1

  1. 00000 - "SQL command not properly ended"

*Cause:

*Action:

存储过程中的第 69 行是 OPEN txtable_cursor FOR query1_str;

我试过使用绑定变量,但仍然出现错误,我可能使用不当。

我的代码可能还有其他问题。如果你能指出这些就太好了。我们目前在 Oracle 12c

Line 69 in the stored proc is OPEN txtable_cursor FOR query1_str;.

显然我们无法 运行 您的代码,因为我们没有您的架构,因此我们无法编译和验证您的动态 SQL。但是,查看您组装的字符串,引人注目的是样板文本和列的串联:

AND RD.RECNAME = ' || recname || 'AND RI.FIELDNAME = ' || fieldname

如果仔细观察,您会发现 'AND RI.FIELDNAME 中的引号后没有 space,这意味着 recname 的值与 AND 连接在一起。那就是你的 ORA-00933。

一旦你解决了这个问题,你可能会 运行 变成 ORA-00936: missing expression。从变量声明中我们知道 recnamefieldname 是字符串,但 你没有将它们视为字符串 。该代码不包含变量周围的任何引号,因此执行的查询会将它们视为列或其他内容。所以这是你需要解决的问题:

AND RD.RECNAME = ''' || recname || ''' AND RI.FIELDNAME = ''' || fieldname ||''''

稍后您可以这样打开游标:

OPEN newrow_cursor FOR query3_str USING 'fieldname';

所以您将参数传递给不包含任何参数占位符的动态查询。那应该抛出

ORA-01006: bind variable does not exist

动态SQL很难,因为它将编译错误转化为运行时间错误。您需要培养冷静的眼光来查看您的代码以发现它们。有用的一件事是使用日志记录来记录动态语句(DBMS_OUTPUT 总比没有好)。通常当我们眼前有真实的陈述时,很容易发现我们的灯笼裤。但如果我们不能,至少我们可以 运行 查询并让编译器指出它们。