【问题标题】:PL SQL Raise Exception when data found发现数据时 PL SQL 引发异常
【发布时间】:2015-03-14 08:21:37
【问题描述】:

我一直在查看预定义的 Oracle pl/SQL 异常。我想在找到数据时引发异常。我已经能够看到NO_DATA_FOUND 异常。但不是相反。最好的方法是什么,或者不建议执行这种操作。

我的程序如下

PROCEDURE CHECK_ASSIGNED AS

PLACEHOLDER INT;   

BEGIN

SELECT v.id
INTO PLACEHOLDER
FROM vinegar v
WHERE NOT EXISTS (
SELECT 1
FROM home h
WHERE h.sid = v.sid
)

END;
-- when data is found it means that and sid does not exist in the home table
-- should raise exception and stop package

【问题讨论】:

    标签: exception plsql oracle11g package


    【解决方案1】:

    “找到数据”没有内置错误,因为 Oracle 不认为查找数据是错误。但是,在特定情况下将这种情况视为错误并不太难。

    这在一定程度上取决于您想对异常做什么。如果您想在过程中以某种方式对其做出反应,您可以定义自己的异常,然后引发它:

    PROCEDURE check_assigned AS
       exception err_data_found;
       placeholder INT;
    BEGIN
       SELECT v.id
       INTO   placeholder
       FROM   vinegar v
       WHERE  NOT EXISTS
                 (SELECT 1
                  FROM   home h
                  WHERE  h.sid = v.sid);
    
       IF SQL%FOUND THEN
          RAISE err_data_found;
       END IF;
    EXCEPTION
       WHEN err_data_found THEN
          NULL;
          --do something
    END;
    

    另一方面,如果你只是想将错误返回给调用者,你可以使用raise_application_error

    PROCEDURE check_assigned AS
       placeholder INT;
    BEGIN
       SELECT v.id
       INTO   placeholder
       FROM   vinegar v
       WHERE  NOT EXISTS
                 (SELECT 1
                  FROM   home h
                  WHERE  h.sid = v.sid);
    
       IF SQL%FOUND THEN
          raise_application_error (-20001,
                                   'Data was found in the vinegar table.');
       END IF;
    END;
    

    如果目标是在存在任何行时引发错误并继续,那么这样做有点危险,因为您可能会触发NO_DATA_FOUNDTOO_MANY_ROWS。您可以通过选择 cmets 中建议的计数来解决此问题,但我更喜欢使用显式光标来避免这些问题。

    PROCEDURE check_assigned AS
       placeholder INT;
    
       CURSOR cur_vinegar_check IS
          SELECT v.id
          INTO   placeholder
          FROM   vinegar v
          WHERE      NOT EXISTS
                        (SELECT 1
                         FROM   home h
                         WHERE  h.sid = v.sid)
                 AND ROWNUM = 1;
    BEGIN
       OPEN cur_vinegar_check;
       FETCH cur_vinegar_check INTO placeholder;
    
       IF SQL%FOUND THEN
          raise_application_error (-20001,
                                   'Data was found in the vinegar table.');
       END IF;
    
       CLOSE cur_vinegar_check;
    END check_assigned;
    

    您会注意到我在查询中添加了AND ROWNUM = 1。这是rownum 在外部查询中可预测的少数情况之一:您只关心是否存在行;你不在乎它是哪一行。如果您有可能会返回大量行,这会带来显着的性能优势。

    【讨论】:

    • 感谢您的回答艾伦。这基本上是包中确认最终要加载的数据是否完整的第一步。因此,如果它不完整,那么它应该在 TOAD 中将错误输出给用户并停止。
    • 我喜欢这个解决方案,但我发现选择一个计数然后检查 IF count_var > 0 更有帮助。这样您就可以检查行是否存在,而不会在该过程中抛出未找到数据错误。
    • @user3268128: 而count 将避免NO_DATA_FOUNDTOO_MANY_ROWS;我不喜欢为此目的使用它,因为它往往需要扫描所有符合条件的行来获取计数,而这个解决方案只需要获取一行。如果要使用count,我建议将rownum = 1 添加到where 子句中,这将告诉数据库它可以在找到一行后停止。
    【解决方案2】:

    您可以引发用户定义的异常。

    PROCEDURE CHECK_ASSIGNED AS
    
    PLACEHOLDER INT;   
    custom_exception  EXCEPTION;
    
    BEGIN
    
    SELECT v.id
    INTO PLACEHOLDER
    FROM vinegar v
    WHERE NOT EXISTS (
    SELECT 1
    FROM home h
    WHERE h.sid = v.sid
    )
    if PLACEHOLDER is not null 
    then
       raise custom_exception;
    end if;
    
    exception
    when custom_exception 
    then 
       --do whatever exception stuff you want here
       DBMS_OUTPUT.PUT_LINE(SQLERRM);
    
    END;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-13
      • 1970-01-01
      • 2013-02-05
      相关资源
      最近更新 更多