Search code examples
sqldatabaseoracleplsqloracle-sqldeveloper

PL/SQL No data found even there should be?


I'm currently learning PL/SQL atm and I have run into an issue with one of my homework questions.

In the below code, I'm getting user input for a province and isolating select results using said province in the declaration of the cursor and trying to run the visitsandtotal procedure but all I'm getting is no data found, why?

user prompt

SET SERVEROUTPUT ON

ACCEPT prov PROMPT 'Enter Province: ';

DECLARE
    customerprov   VARCHAR2(4000);
    customername   VARCHAR2(4000);
    visits         NUMBER;
    total          FLOAT;
    CURSOR prov_cursor is
    Select custprovince, custname
    into customerprov, customername
    from si.customer
    where upper(custprovince) = '&prov';
    
BEGIN
    for c in prov_cursor loop
        visitsandtotal(c.custname, visits, total);
        dbms_output.put_line('Name: ' || c.custname || ' Visits: ' || visits || ' Total Labor Cost: ' || total);
    end loop;
END;

Procedure

  CREATE OR REPLACE PROCEDURE visitsandtotal (
    userinput    IN  VARCHAR2
    , visits         OUT   NUMBER
    , total          OUT   FLOAT
) IS
BEGIN
    SELECT
        COUNT(*) AS visits
        , SUM(s.laborcost) AS totalcost
    INTO
    visits
    , total
    FROM
        si.customer   c
        INNER JOIN si.servinv    s ON c.custname = s.custname
    WHERE
        s.custname = userinput
    GROUP BY
        c.custname
        , s.custname ;

END;

Error

Error report -
ORA-01403: no data found
ORA-06512: at "S6_TRAN84.VISITSANDTOTAL", line 7
ORA-06512: at line 11
01403. 00000 -  "no data found"
*Cause:    No data was found from the objects.
*Action:   There was no data from the objects which may be due to end of fetch.

Solution

  • I cannot comment due to less number of reputation.

    NO_DATA_FOUND error comes from the procedure where you have where clause and group by..

    and if no records with parameter "userinput" leads to the exception.

    I would suggest to change the procedure as we certainly don't need the group by custname as the custname is part of where clause;

    CREATE OR REPLACE PROCEDURE visitsandtotal 
     (
        userinput IN  VARCHAR2
       ,visits    OUT NUMBER
       ,total     OUT FLOAT
    ) 
    IS
    BEGIN
      SELECT COUNT(*) AS visits
            ,SUM(s.laborcost) AS totalcost
      INTO   visits
            ,total
      FROM   si.customer c
      INNER  JOIN si.servinv s
      ON     c.custname = s.custname
      WHERE  s.custname = userinput;
      --removed  group by as custname is part of where clause  
    END visitsandtotal;
    

    But for whatever reason if you insists to keep the group by clause, you have to handle NO_DATA_FOUND exception explicitly in the procedure visitsandtotal

    CREATE OR REPLACE PROCEDURE visitsandtotal 
     (
        userinput IN  VARCHAR2
       ,visits    OUT NUMBER
       ,total     OUT FLOAT
    ) 
    IS
    BEGIN
      SELECT COUNT(*) AS visits
            ,SUM(s.laborcost) AS totalcost
      INTO   visits
            ,total
      FROM   si.customer c
      INNER  JOIN si.servinv s
      ON     c.custname = s.custname
      WHERE  s.custname = userinput;
      GROUP  BY c.custname,s.custname;
      -- you dont need to mention custname from both table as join is in place
    EXCEPTION 
      WHEN no_data_found THEN
        --HERE - write your exception code whatever you like to add
    END visitsandtotal;