尝试从游标中获取PLS-00103错误

时间:2019-01-10 10:03:56

标签: oracle plsql database-cursor

我正在尝试编写一个游标。我尝试匹配示例的语法,但总是在FETCH语句上出现编译失败。

CREATE OR REPLACE PROCEDURE IFSAPP.CLEAR_OLD_PURCHASE_ORDERS (cPlannedDelDate in varchar2) IS

     -- cursor to get all the purchase orders's that have lines in released state that 
    CURSOR c1 IS 
        SELECT DISTINCT PO.ORDER_NO
        FROM PURCHASE_ORDER PO, PURCHASE_ORDER_LINE_NOPART POLN
        WHERE PO.ORDER_NO = POLN.ORDER_NO 
        AND POLN.STATE = 'Released'
        AND POLN.PLANNED_DELIVERY_DATE < TO_DATE(cPlannedDelDate, 'DD/MM/YYYY');

BEGIN

    DECLARE corder_no varchar2(12);

    OPEN c1;    
    LOOP
        FETCH c1 INTO corder_no;
        EXIT WHEN c1%NOTFOUND;
        DBMS_OUTPUT.PUT_LINE(corder_no);
    END LOOP;
    CLOSE c1;
END CLEAR_OLD_PURCHASE_ORDERS;
/
LINE/COL ERROR
-------- -----------------------------------------------------------------
17/9     PLS-00103: Encountered the symbol "FETCH" when expecting one of the following:
         constant exception <an identifier>
         <a double-quoted delimited-identifier> table columns long
         double ref char time timestamp interval date binary national
         character nchar
21/5     PLS-00103: Encountered the symbol "CLOSE" when expecting one of the following:
         end not pragma final instantiable order overriding static
         member constructor map

谁能看到我要去哪里错了?

1 个答案:

答案 0 :(得分:1)

问题实际上是在声明局部变量以及使用DECLARE关键字的地方。这将开始一个新的内部PL / SQL块,但随后您有了OPEN等,而无需使用新的BEGIN继续该模式。

尽管您不需要子块,只需将局部变量声明上移到现有的BEGIN之前,然后丢失多余的DECLARE

CREATE OR REPLACE PROCEDURE IFSAPP.CLEAR_OLD_PURCHASE_ORDERS (cPlannedDelDate in varchar2) IS

     -- cursor to get all the purchase orders's that have lines in released state that 
    CURSOR c1 IS 
        SELECT DISTINCT PO.ORDER_NO
        FROM PURCHASE_ORDER PO, PURCHASE_ORDER_LINE_NOPART POLN
        WHERE PO.ORDER_NO = POLN.ORDER_NO 
        AND POLN.STATE = 'Released'
        AND POLN.PLANNED_DELIVERY_DATE < TO_DATE(cPlannedDelDate, 'DD/MM/YYYY');

    corder_no varchar2(12);

BEGIN

    OPEN c1;    
    LOOP
        FETCH c1 INTO corder_no;
        EXIT WHEN c1%NOTFOUND;
        DBMS_OUTPUT.PUT_LINE(corder_no);
    END LOOP;
    CLOSE c1;
END CLEAR_OLD_PURCHASE_ORDERS;
/

顺便说一句,您应该考虑使用ANSI连接语法,而不是古老的逗号分隔的FROM子句语法。而且使用隐式游标循环会更简单:

CREATE OR REPLACE PROCEDURE IFSAPPCLEAR_OLD_PURCHASE_ORDERS (cPlannedDelDate in varchar2) IS
BEGIN
    FOR r1 IN (
        SELECT DISTINCT PO.ORDER_NO
        FROM PURCHASE_ORDER_LINE_NOPART POLN
        JOIN PURCHASE_ORDER PO
        ON PO.ORDER_NO = POLN.ORDER_NO 
        WHERE POLN.STATE = 'Released'
        AND POLN.PLANNED_DELIVERY_DATE < TO_DATE(cPlannedDelDate, 'DD/MM/YYYY')
    ) LOOP
        DBMS_OUTPUT.PUT_LINE(r1.order_no);
    END LOOP;
END CLEAR_OLD_PURCHASE_ORDERS;
/

我通常也希望将过程参数声明为所需的数据类型,即DATE,因此您可以在查询中使用它而无需转换它;并使其成为调用者的问题,以输入正确的数据类型。