处理此Oracle ORA-01403的正确方法是什么:没有找到数据异常?

时间:2012-02-01 22:13:41

标签: oracle exception stored-procedures

我有一个数据库表,我或多或少像队列一样对待。我正在尝试从中获取单个项目。这是有效的,除非SELECT..INTO失败(如果队列中只有一个项目,并且不同机器上的两个用户尝试并获取它,则可能会发生这种情况;只有一个将获胜)。

这会导致熟悉的 ORA-01403:找不到数据异常。我试图更改SP,以便它在这种情况下返回NULL记录 - 同样的结果你得到它一个查询无法找到任何记录 - 但无济于事。我在这里做错了。

PROCEDURE sp_GetNextEmailFromQueue (pAgentId IN NUMBER, pRecs OUT recordSet)
  IS
  EMAIL_ID INTEGER;
  BEGIN

     SELECT id INTO EMAIL_ID FROM
           (SELECT id, is_replied_to, is_being_worked, date_received 
           FROM SSQ_EMAILS
           WHERE is_replied_to = 0 AND is_being_worked =0
           ORDER BY date_received ASC)
     WHERE rownum = 1;


    UPDATE SSQ_EMAILS x 
             SET x.is_being_worked = 1,
                 x.agent_id = pAgentId,
                 x.work_started_date = SYSDATE
             WHERE x.id = EMAIL_ID;

    OPEN pRecs FOR
      SELECT x.id,
             x.message_id,
             x.to_email,
             x.from_email,
             x.subject,
             x.message,
             x.date_received,
             x.href_link,
             x.is_being_worked,
             x.work_started_date,
             x.is_replied_to
        FROM SSQ_EMAILS x
        WHERE x.id = EMAIL_ID;

        EXCEPTION
          WHEN no_data_found 
            THEN 
              OPEN pRecs FOR
              SELECT NULL
              FROM SSQ_EMAILS;

  END;

5 个答案:

答案 0 :(得分:7)

我将异常处理程序放在实际导致错误抛出的代码片段周围。如果email_id为NULL,则UPDATE将不会更新任何行,SELECT将不会返回任何行。

PROCEDURE sp_GetNextEmailFromQueue (pAgentId IN NUMBER, pRecs OUT recordSet)
  IS
  EMAIL_ID INTEGER;
  BEGIN
    BEGIN
      SELECT id 
        INTO EMAIL_ID 
        FROM (SELECT id, is_replied_to, is_being_worked, date_received 
                FROM SSQ_EMAILS
               WHERE is_replied_to = 0 AND is_being_worked =0
               ORDER BY date_received ASC)
       WHERE rownum = 1;
    EXCEPTION
      WHEN no_data_found 
      THEN
        email_id := null;
    END;

    UPDATE SSQ_EMAILS x 
             SET x.is_being_worked = 1,
                 x.agent_id = pAgentId,
                 x.work_started_date = SYSDATE
             WHERE x.id = EMAIL_ID;

    OPEN pRecs FOR
      SELECT x.id,
             x.message_id,
             x.to_email,
             x.from_email,
             x.subject,
             x.message,
             x.date_received,
             x.href_link,
             x.is_being_worked,
             x.work_started_date,
             x.is_replied_to
        FROM SSQ_EMAILS x
        WHERE x.id = EMAIL_ID;
  END;

请注意,此代码不会阻止两个不同的调用者在同一行上工作。如果两个会话同时调用此过程,则两者都完全可能选择同一行。如果您想阻止这种情况,SELECT需要使用FOR UPDATE子句锁定它所选择的行。

答案 1 :(得分:4)

在这种情况下,您无能为力:

exception
  when no_data_found then
    null;
end;

这会在pRecs对吗?

中返回null

修改

第二种方法:

cursor c_mail is
  SELECT id  
    FROM
       (SELECT id, is_replied_to, is_being_worked, date_received 
          FROM SSQ_EMAILS
         WHERE is_replied_to = 0 AND is_being_worked =0
         ORDER BY date_received ASC)
   WHERE rownum = 1;
....
open c_mail;
fetch c_mail into email_id; -- no_data_found not happens
close c_mail;

答案 2 :(得分:2)

如何避免异常处理:

/* returns X */
SELECT DUMMY FROM DUAL WHERE 1 = 1;

/* no data found */
SELECT DUMMY FROM DUAL WHERE 1 = 0;

/* returns NULL */
SELECT MIN(DUMMY) FROM DUAL WHERE 1 = 0;

答案 3 :(得分:1)

如果表中没有记录,

select null from ssq_emails仍将获得1403。我不确定你想在异常处理程序中做任何事情;不确定你的来电者如何处理pRecs为空。

答案 4 :(得分:1)

通过这样做解决了这个问题:

EXCEPTION
   WHEN no_data_found THEN 
      OPEN pRecs FOR
      SELECT NULL
      FROM SSQ_EMAILS  s
      WHERE s.id IS NULL;

它的工作原因是必须打开RefCursor。我需要一个空的结果,这似乎是一种安全的方法来保证,因为ID是PK而不能为null。