Как правильно обращаться с этим Oracle ORA-01403: исключение не найдено? - PullRequest
9 голосов
/ 02 февраля 2012

У меня есть таблица БД, которую я более или менее воспринимаю как очередь. Я пытаюсь извлечь из него один предмет. Это работает, за исключением случаев, когда происходит сбой 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 ]

7 голосов
/ 02 февраля 2012

Я бы поместил обработчик исключений вокруг фрагмента кода, который фактически вызывает ошибку.Если 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.

4 голосов
/ 02 февраля 2012

Вы ничего не можете сделать в этом случае:

exception
  when no_data_found then
    null;
end;

Это вернет ноль в pRecs верно?

РЕДАКТИРОВАТЬ

Второйподход:

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 голосов
/ 30 апреля 2014

Как насчет этого, избегая обработки исключений:

/* 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;
1 голос
/ 02 февраля 2012

Решил, сделав это:

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

Это работает, потому что RefCursor должен быть открыт. Мне нужен пустой результат, и это кажется безопасным способом гарантировать это, потому что идентификатор - это PK и не может быть нулевым.

1 голос
/ 02 февраля 2012

select null from ssq_emails все равно получит 1403, если в таблице нет записей.Я не уверен, что вы хотите что-то делать в обработчике исключений;не знаю, как ваш собеседник справится с тем, что pRecs пусто.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...