【问题标题】:PL/SQL : Encountered the symbol "END"PL/SQL : 遇到符号“END”
【发布时间】:2012-10-23 22:26:40
【问题描述】:

即使我仔细检查了代码,我也会收到以下错误。我不知道我错过了什么。

行/列错误


31/1 PLS-00103:在期待其中一个时遇到符号“END” 以下:

代码:

CREATE OR REPLACE PROCEDURE sp_ssjm_newworkorder
(   workorderno IN NUMBER,
company     IN CHAR,
attention   IN CHAR,
datedue     IN DATE,
loggedby    IN CHAR
)

AS  id     NUMBER;
today         DATE:=SYSDATE;
BEGIN
SELECT  client_id   --grab client_id
INTO id 
FROM    ssjm_client
WHERE ssjm_client.name=company;

IF id IS NULL THEN  --check if client exists by checking if client_id is there
    dbms_output.put_line('Please create client first');
    GOTO the_end;
ELSE
    INSERT INTO ssjm_workorder      VALUES(workorderno,workorderno,company,loggedby,attention,'Received',today,datedue,id);
END IF;

EXCEPTION
    WHEN OTHERS THEN
    raise_application_error(-20999,'An error occured in' ||
        SQLCODE || '-ERROR-' || SQLERRM);

<<the_end>>

END sp_ssjm_newworkorder;

【问题讨论】:

    标签: sql oracle stored-procedures plsql sqlplus


    【解决方案1】:

    您的代码中有几个地方需要注意:

    1. 出现该错误的原因是标签 &lt;&lt;the_end&gt;&gt; 应该放在 EXCEPTION 部分之前。
    2. 标签后需要操作符。因此,如果您想跳转到存储过程的末尾并且不需要其他操作,则应使用 NULL 运算符。

    为此,您的代码应如下所示:

    IF id IS NULL THEN  --check if client exists by checking if client_id is there
        dbms_output.put_line('Please create client first');
        GOTO the_end;
    ELSE
        INSERT INTO ssjm_workorder
     VALUES(workorderno,workorderno,company,loggedby
           ,attention,'Received',today,datedue,id);
    END IF;
    
    <<the_end>>
    NULL;
    
    EXCEPTION
        WHEN OTHERS THEN
        raise_application_error(-20999,'An error occured in' ||
            SQLCODE || '-ERROR-' || SQLERRM);
    END sp_ssjm_newworkorder;
    

    尽量避免无条件分支。使用 GOTO 运算符是非常非常不好的做法。它扼杀了可读性,这样的代码很难调试。这会让你和所有在你之后看那个代码的人都头疼。此外,如果查询

    SELECT  client_id   --grab client_id
    INTO id 
    FROM    ssjm_client
    WHERE ssjm_client.name=company;
    

    不返回任何行,异常NO_DATA_FOUND 将立即引发并暂停代码的执行。所以IF id IS NULL THEN 条件永远不会被评估。您可以通过删除该条件并在代码的EXCEPTION 部分添加NO_DATA_FOUND 异常处理程序来重写您的代码。当然,正如@Rob van Wijk 在评论中正确指出的那样

    但可以进一步清理代码。 today 变量可以被删除并且 WHEN OTHERS 绝对应该被删除。就像现在一样,它只是 将错误转换为更长的错误消息,而无需更多详细信息,并且 最重要的是:它掩盖了真正错误所在的行号 发生了。

    不需要today变量,SYSDATE可以直接用在insert语句的values子句中,WHEN OTHERS也可以去掉。

    CREATE OR REPLACE PROCEDURE sp_ssjm_newworkorder
    (
    workorderno IN NUMBER,
    company     IN CHAR,
    attention   IN CHAR,
    datedue     IN DATE,
    loggedby    IN CHAR
    )
    AS  
      id     NUMBER;
    BEGIN
      SELECT client_id   --grab client_id
        INTO id
        FROM ssjm_client
       WHERE ssjm_client.name=company;
    
        INSERT INTO ssjm_workorder      
          VALUES(workorderno,workorderno,company,loggedby
                ,attention,'Received',SYSDATE,datedue,id);
    
    EXCEPTION
        when NO_DATA_FOUND
        then dbms_output.put_line('Please create client first');
    END sp_ssjm_newworkorder;
    

    【讨论】:

    • 很好的答案 (+1),但可以进一步清理代码。 today 变量可以被删除,而 WHEN OTHERS 绝对应该被删除。就像现在一样,它只是将错误转换为更长的错误消息,没有更多细节,最重要的是:它掩盖了发生真正错误的行号。
    • 您能否解释一下为什么不需要 WHEN OTHERS 例外。问候
    • @Polppan 当引发NO_DATA_FOUND 以外的异常时,错误消息将为我们提供一个行号,其中raise_application_error 函数已被调用,而不是遇到异常的语句行。因此,如果我们有多个 insert 语句并且其中一个引发 unique constraint violated 异常,我们将不知道是哪一个。但是我们可以保留WHEN OTHERS 并使用SQLERRM 结合DBMS_UTILITY.FORMAT_ERROR_BACKTRACE 函数(10g 以上)来获取错误消息和发生异常的行以记录错误。
    • @NicholasKrasnov 所以WHEN_OTHERSSQLERRM 的组合是必需的?
    • @Polppan 记录错误然后传播异常会很有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    相关资源
    最近更新 更多