简体   繁体   中英

Why is my exception not being raised?

I'm new to PL/SQL and Oracle. I'm working on a small code block that generates the top 5 values in a column. I'm trying to get an exception to throw when there are less than 5 rows of data in the table.

DELETE FROM CREDIT_CARD;
SELECT * FROM CREDIT_CARD;
Insert into CREDIT_CARD values (6011956844573649,'550',892);
Insert into CREDIT_CARD values (5250335443644204,'15000',661);


DECLARE
   CURSOR Final_Q2_Cursor is
      SELECT CREDITCARDNUMBER,CREDITCARDLIMIT,CUSTOMERID FROM CREDIT_CARD
         ORDER BY CREDITCARDLIMIT DESC;   -- start with highest paid employee

  aCardLimt NUMBER(8,2);
  aCardNum NUMBER(16);
  aCustId INT;
BEGIN
   OPEN  Final_Q2_Cursor ;
   FOR i IN 1..5 LOOP
      FETCH Final_Q2_Cursor INTO aCardNum, aCardLimt, aCustId;
      EXIT WHEN Final_Q2_Cursor%NOTFOUND; 
      INSERT INTO TOP_FIVE_CREDIT_LIMITS VALUES (aCardLimt, aCardNum, aCustId);
   END LOOP;
   CLOSE Final_Q2_Cursor;
EXCEPTION 
   WHEN no_data_found THEN 
      dbms_output.put_line('No such customer!'); 
   WHEN others THEN 
      dbms_output.put_line('Error!');    
END;
/

I only insert 2 rows of data, but it is still processing everything. Why?

Here's an example of where you interrogate the cursor attribute to decide if you need to explicitly raise an error

SQL> create table TOP_FIVE_CREDIT_LIMITS (CREDITCARDLIMIT int, CREDITCARDNUMBER int, CUSTOMERID int );

Table created.

SQL> create table CREDIT_CARD (
  2        CREDITCARDNUMBER int,CREDITCARDLIMIT int,CUSTOMERID int );

Table created.

SQL>
SQL> DELETE FROM CREDIT_CARD;

0 rows deleted.

SQL> SELECT * FROM CREDIT_CARD;

no rows selected

SQL> Insert into CREDIT_CARD values (6011956844573649,'550',892);

1 row created.

SQL> Insert into CREDIT_CARD values (5250335443644204,'15000',661);

1 row created.

SQL>

Pl/SQL:

SQL> set serverout on
SQL> DECLARE
  2     CURSOR Final_Q2_Cursor is
  3        SELECT CREDITCARDNUMBER,CREDITCARDLIMIT,CUSTOMERID FROM CREDIT_CARD
  4           ORDER BY CREDITCARDLIMIT DESC;   -- start with highest paid employee
  5
  6    aCardLimt NUMBER(8,2);
  7    aCardNum NUMBER(16);
  8    aCustId INT;
  9  BEGIN
 10     OPEN  Final_Q2_Cursor ;
 11     FOR i IN 1..5 LOOP
 12        FETCH Final_Q2_Cursor INTO aCardNum, aCardLimt, aCustId;
 13
 14        if Final_Q2_Cursor%NOTFOUND and i < 5 then
 15             raise_application_error(-20000,'Ran out of rows before I got to 5');
 16        end if;
 17        EXIT WHEN Final_Q2_Cursor%NOTFOUND;
 18        INSERT INTO TOP_FIVE_CREDIT_LIMITS VALUES (aCardLimt, aCardNum, aCustId);
 19     END LOOP;
 20     CLOSE Final_Q2_Cursor;
 21  EXCEPTION
 22     WHEN no_data_found THEN
 23        dbms_output.put_line('No such customer!');
 24     WHEN others THEN
 25        dbms_output.put_line('Error!');
 26  END;
 27  /
Error!

PL/SQL procedure successfully completed.

but I stress, that's not a smart way of doing things (although if its your assignment..then fine). Generally we try keep the code nice and lean by using SQL where possible, and we never like to catch all errors in when-others without propagating them back to the calling environment. So you could also recast your code like follows:

SQL> set serverout on
SQL> BEGIN
  2    insert into TOP_FIVE_CREDIT_LIMITS
  3    select *
  4    from
  5      ( SELECT CREDITCARDNUMBER,CREDITCARDLIMIT,CUSTOMERID FROM CREDIT_CARD
  6        ORDER BY CREDITCARDLIMIT DESC
  7      )
  8    where rownum <= 5;
  9
 10    if sql%rowcount = 0 then
 11         raise_application_error(-20000,'No rows were found at all');
 12    elsif sql%rowcount < 5 then
 13         raise_application_error(-20000,'Ran out of rows before I got to 5');
 14    end if;
 15
 16  END;
 17  /
BEGIN
*
ERROR at line 1:
ORA-20000: Ran out of rows before I got to 5
ORA-06512: at line 13

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM