查找异常 (PL/SQL)

Posted

技术标签:

【中文标题】查找异常 (PL/SQL)【英文标题】:Finding exception (PL/SQL) 【发布时间】:2015-05-21 16:09:07 【问题描述】:

我在 Oracle 中运行代码,要求用户输入路线类型,然后程序根据用户输入的路线以及获取的行数获取最长和最短的路线。我需要在代码中添加任何异常,并且我正在尝试考虑在这种情况下我可以添加什么样的异常。我正在考虑添加一个异常,如果获取的行

我的代码是:

SET SERVEROUTPUT ON;
SET VERIFY OFF

DECLARE
v_type VARCHAR2 (20);
min_length NUMBER;
max_length NUMBER;
v_count NUMBER;


BEGIN
v_type := '&InsertTypeRoute';

IF v_type = 'Multi-Lane Divided' OR
v_type = 'Paved Divided' OR
v_type = 'Paved Undivided' THEN
SELECT MIN(LENGTH_KM), MAX(LENGTH_KM), COUNT(LENGTH_KM) INTO min_length, max_length, v_count
FROM TBLROUTE WHERE TYPE = v_type;

DBMS_OUTPUT.PUT_LINE('The minimum length is: ' || TO_CHAR(min_length));
DBMS_OUTPUT.PUT_LINE('The maximum length is: ' || TO_CHAR(max_length));
DBMS_OUTPUT.PUT_LINE ('Total number of '|| v_type ||' route is: ' || TO_CHAR(v_count));

ELSE
DBMS_OUTPUT.PUT_LINE ('Route type cannot be found');
END IF;

/*
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('Route type cannot be found'); */
END;
/

这些异常呢?它们在这种情况下是否合适?

EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('Data not found');


WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('This program encountered an error');

【问题讨论】:

我不确定我是否理解您提出的问题。如果SELECT INTO 返回除 1 行以外的任何内容,您是否问会引发什么异常?如果查询返回超过 1 行,您将收到 too_many_rows 异常;如果查询返回 0 行,您将收到 no_data_found 异常。这就是你要问的吗?还是你在问别的?没有IFELSE 没有多大意义。 EXCEPTION WHEN OTHERS THEN NULL (write error to log table passing in known paramaters and values and procedure package encountering the error); inline 您可以处理已知错误,例如WHEN no_data_found THENWHEN too_many_rows THEN 我会使用这种类型的逻辑来捕获所有错误并将它们记录下来,以便我们可以查看问题是否未解决,并且有日志来解决它们作为以后的增强功能 我正在尝试找到一个异常,如果路由类型的行数或更少,它将给我一个错误,因为每个路由类型应该有比 1 多得多的记录。 【参考方案1】:

如果您使用 WHEN_OTHERSRAISE,建议添加 SQLCODESQLERRM 这会告诉你究竟出了什么问题。

EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR MESSAGE :' || SQLCODE || ' :' || SQLERRM );
RAISE;

【讨论】:

【参考方案2】:

“在这种情况下它们合适吗?”

处理这样的异常被普遍认为是不好的做法。它吞下了真正的异常,因此用户知道某事失败了,但他们完全不知道是什么。

 WHEN OTHERS THEN
 DBMS_OUTPUT.PUT_LINE('This program encountered an error');

在这种情况下,什么都不做比做那个更好。

在您的情况下,我建议您依靠默认的 PL/SQL NO_DATA_FOUND 异常来处理无记录,并在只有一条记录时引发定制异常。像这样的:

DECLARE
    v_type VARCHAR2 (20);
    min_length NUMBER;
    max_length NUMBER;
    v_count NUMBER;
    -- user-defined exception
    x_single_route exception;
    pragme expcetion_init(x_single_route, -20001);

BEGIN
    v_type := '&InsertTypeRoute';

    IF v_type = 'Multi-Lane Divided' OR
        v_type = 'Paved Divided' OR
        v_type = 'Paved Undivided' 
    THEN
        SELECT MIN(LENGTH_KM), MAX(LENGTH_KM), COUNT(LENGTH_KM) INTO min_length, max_length, v_count
        FROM TBLROUTE WHERE TYPE = v_type;

    IF v_count > 1 THEN
        DBMS_OUTPUT.PUT_LINE('The minimum length is: ' || TO_CHAR(min_length));
        DBMS_OUTPUT.PUT_LINE('The maximum length is: ' || TO_CHAR(max_length));
        DBMS_OUTPUT.PUT_LINE ('Total number of '|| v_type ||' route is: ' || TO_CHAR(v_count));
    ELSE
        raise x_single_route;
    END IF;

EXCEPTION
    WHEN x_single_route THEN 
        DBMS_OUTPUT.PUT_LINE ('Route has only one leg');
    WHEN NO_DATA_FOUND THEN
        DBMS_OUTPUT.PUT_LINE ('Route type cannot be found'); 
END;
/ 

一般来说,引发异常是一种很好的做法:用户想知道什么时候出了问题。 (虽然这似乎是一个面向用户的程序,所以它略有不同。)

   ... 
EXCEPTION
    WHEN x_single_route THEN 
        DBMS_OUTPUT.PUT_LINE ('Route has only one leg');
        RAISE;
    WHEN NO_DATA_FOUND THEN
        ....

【讨论】:

【参考方案3】:

您可以使用RAISE_APPLICATION_ERROR 过程在用户定义的范围 (-20000..-20999) 中引发特定异常,然后定义一个异常以便捕获它。像下面这样的东西应该可以工作:

DECLARE
  SOMETHING_UNWANTED_HAPPENS BOOLEAN := TRUE;
BEGIN
  IF SOMETHING_UNWANTED_HAPPENS THEN
    RAISE_APPLICATION_ERROR(-20001, 'Something I didn''t want happened');
  END IF;
EXCEPTION
  WHEN OTHERS THEN
    IF SQLCODE = -20001 THEN
      DBMS_OUTPUT.PUT_LINE('My user-defined exception was raised');
    -- Do whatever else you want to do to handle this exception
    ELSE
      DBMS_OUTPUT.PUT_LINE('Something else happened');
    END IF;
END;

或者您可以声明一个 EXCEPTION 变量,使用 PRAGMA EXCEPTION_INIT 对其进行初始化,然后像任何其他异常一样使用它:

DECLARE
  my_exception EXCEPTION;
  PRAGMA EXCEPTION_INIT(my_exception, -20001);

  SOMETHING_UNWANTED_HAPPENS BOOLEAN := TRUE;
BEGIN
  IF SOMETHING_UNWANTED_HAPPENS THEN
    RAISE my_exception;
  END IF;
EXCEPTION
  WHEN my_exception THEN
    DBMS_OUTPUT.PUT_LINE('My user-defined exception was raised');

  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('Something else happened');
END;

【讨论】:

以上是关于查找异常 (PL/SQL)的主要内容,如果未能解决你的问题,请参考以下文章

异常后停止 PL/SQL 代码(PL/SQL、ORACLE)

PL/SQL 引发处理异常

PL/SQL 异常不会引发

PL/SQL:捕获编号异常?

PL/SQL 异常以啥顺序引发?

PL/SQL 异常翻译