¿Cuál es la forma correcta de tratar este Oracle ORA-01403: no se encontraron datos de excepción?

I have a DB table that I am more or less treating like a queue. I'm trying to fetch a single item from it. This works, except when the SELECT..INTO fails (which can happen if there is only one item in the queue and two users on separate machines try and fetch it; only one is going to win).

This leads to the familiar ORA-01403: no se encontraron datos exception. I tried to change the SP so that it would return NULL record in this case - the same sort of result you'd get it a query couldn't find any records - but to no avail. I am doing something wrong here.

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;

preguntado el 01 de febrero de 12 a las 22:02

5 Respuestas

I'd put the exception handler around the piece of code that is actually causing the error to be thrown. If email_id is NULL, the UPDATE will not update any rows and the SELECT will not return any rows.

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;

Be aware, though, that this code does not prevent two different callers from working on the same row. If two session call this procedure at the same time, it's entirely possible that both will select the same row. If you want to prevent that, the SELECT would need to lock the row it selected with the FOR UPDATE cláusula.

Respondido 02 Feb 12, 03:02

You can do nothing in this case:

exception
  when no_data_found then
    null;
end;

This will return null in pRecs ¿derecho?

EDITAR

Segundo enfoque:

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;

Respondido 02 Feb 12, 02:02

Didn't seem to be the case Sergio. I did try that, but I may have screwed something up. I did get it worked by doing select ID from ssq_emails where ID IS NULL, which isn't possible because it's a PK field, so it returns an empty refCursor, just like I wanted. - Chris Holmes

Sergio, what that actually does is give me a ORA-24338: statement handle not executed. And I think it has to do with the RefCursor (pRecs) not actually being opened, from what I can get of the documentation. My C# statement on the outside of this is expecting a RefCursor. - Chris Holmes

Ok, so how about use one cursor instead of "select into"? - user800014

How about this, avoiding exception handling:

/* 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;

Respondido 30 Abr '14, 16:04

select null from ssq_emails will still get a 1403 if there are no records in the table. I'm not sure you want to do anything in the exception handler; not sure how your caller will deal with pRecs being empty though.

Respondido 02 Feb 12, 02:02

Yeah, and more interesting was, select NULL from ssq_emails returns n rows where n= whatever is in the table. So when I tried to run it I started getting LINQ errors in my C# statement because SingleOrDefault() threw up. Got it in the end. - Chris Holmes

Solved it by doing this:

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

It works because the RefCursor has to be opened. I need an empty result, and this seems like a safe way to guarantee that, because the ID is the PK and cannot be null.

Respondido 02 Feb 12, 02:02

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.