How to get NO_DATA_FOUND exception to output when using COUNT(*)? - sql

I am trying to determine why my exception output is not returning correctly.
This is for Oracle SQL Developer, practicing with PL/SQL. I can provide the table code if requested.
SET serveroutput on
CREATE OR REPLACE Procedure GetPermissions(user IN VARCHAR, docNum OUT
INTEGER)
IS
BEGIN
SELECT count(*) INTO docNum FROM UserPermissions where UserName=user;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('Nothing found for this username');
END;
/
DECLARE
doc_count INTEGER;
BEGIN
doc_count:=0;
GetPermissions('Steve', doc_count);
dbms_output.put_line(' Number of documents: ' || doc_count);
END;
/
I am expecting the exception to return its output (nothing found) when 'Steve' is ran through as that is not a username in the table I created. When running currently is just shows "Number of documents: 0".

COUNT always returns a result, in this case, it returns a single row with 0 in it:
COUNT(*)
--------
0
NO_DATA_FOUND occurs only when the SELECT INTO query doesn't return any row.
For example, NO_DATA_FOUND will be thrown, if you try to select permission for a given user:
SELECT permission
INTO p_permission
FROM UserPermissions
WHERE UserName=user;
In this case, the query will return an empty result.

select into query returns with No_Data_found exception when the out put of the query is no rows. not when it is 0.
Another exception you get with select into clause is too many rows where the query returns more that 1 row and you are trying to assign all those to a variable.

Related

Raise exception in stored procedure based on view entries

I have a stored procedure. I would like to implement the below logic, which I have written in pseudocode.
If the below query has one of more entries:
SELECT
NULL
FROM
table1
WHERE
condition
GROUP BY
column
HAVING
COUNT(1) > 1
UNION ALL
SELECT
NULL
FROM
table1 a
WHERE
condition
AND EXISTS (
SELECT
NULL
FROM
table2 b
WHERE
condition
);
Then raise an exception and stop the stored procedure.
Here is an example of raising an exception if a particular value is found from a query:
declare
somevar dual.dummy%type;
begin
select 'Y' into somevar
from dual;
if somevar = 'Y' then
raise_application_error(-20123, 'Hull breach on deck 15. Abandon ship.');
end if;
end;
The "select from dual" can be any query, so feel free to substitute your unions and counts (though we should really stick to the standard count(*), not count('Dracula') etc).
Let's do this with the sample emp/dept schema - just plug in your own statement for your use case. You do need to declare since in pl/sql you cannot "just select". You always need to select into a variable. I usually just select the number 1 into a dummy variable of type number. The trick is to raise the exception after the SELECT INTO and do nothing on NO_DATA_FOUND.
You can use named exceptions to distinguish different cases but since a no data found will throw an exception you have to do each of the cases in its own block. The cleanest is to handle all named exceptions in the final exception block.
DECLARE
l_dummy NUMBER;
king_exists EXCEPTION;
dave_exists EXCEPTION;
BEGIN
BEGIN
SELECT 1 INTO l_dummy FROM emp WHERE ename = 'DAVE';
RAISE dave_exists;
EXCEPTION WHEN NO_DATA_FOUND THEN
NULL;
END;
BEGIN
SELECT 1 INTO l_dummy FROM emp WHERE ename = 'KING';
RAISE king_exists;
EXCEPTION WHEN NO_DATA_FOUND THEN
NULL;
END;
EXCEPTION
WHEN dave_exists THEN
raise_application_error(-20000,'My expection error message');
WHEN king_exists THEN
raise_application_error(-20001,'King exists');
END;
/

ORACLE Error report ORA-01422: exact fetch returns more than requested number of rows?

I am trying to run the below code but it give me error. I am new in ORACLE and any help are welcome, also what additions can be made to the code to ensure this error is captured in the future and a meaningful message is provided for the user thanks.
DECLARE
V_lname VARCHAR2(15);
BEGIN
SELECT last_name INTO v_lname
FROM employees
WHERE first_name='John';
DBMS_OUTPUT.PUT_LINE ('John' 's last name is : '
|| v_lname);
END;
and I am having this error;
Error report
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at line 4
The error message is clear, you can only fetch one value into your v_lname variable so PL/SQL is erroring to say that your query is trying to return multiple rows.
Either:
Change the query so it only returns one row
Change the PL/SQL so that it can handle multiple rows.
I'll demo the second option, as I have no idea which employee named 'John' you might want.
begin
for rJohn in
(select last_name
from employees
where first_name='John'
) loop
dbms_output.put_line ('John''s last name could be : '|| rJohn.last_name);
end loop;
end;
/
Here I use an implicit cursor for loop (https://docs.oracle.com/en/database/oracle/oracle-database/19/lnpls/cursor-FOR-LOOP-statement.html#GUID-62C9A3C8-82F9-468F-8D84-81672E67736D) to run a dbms_output.put_line call per row it finds for your query.
Two useless options. Why useless? Because you should probably rewrite query so that it returns only desired "John".
Also, a suggestion: let variable reference column's datatype, don't fix it to e.g. varchar2(15). What if you - some day in the future - have to alter the table and enlarge the column to varchar2(25)? Your code will miserably fail.
The first option: use aggregate function, such as MIN or MAX:
DECLARE
V_lname employees.last_name%type; --> this
BEGIN
SELECT MAX(last_name) --> this
INTO v_lname
FROM employees
WHERE first_name = 'John';
DBMS_OUTPUT.PUT_LINE ('John' 's last name is : ' || v_lname);
END;
Another option is to use ROWNUM:
DECLARE
V_lname employees.last_name%type; --> this
BEGIN
SELECT last_name
INTO v_lname
FROM employees
WHERE first_name = 'John'
AND rownum = 1; --> this
DBMS_OUTPUT.PUT_LINE ('John' 's last name is : ' || v_lname);
END;

Too Many Rows throwing but only one is selected

I have this procedure which just deletes a row based on a column field called AppID. This procedure get's a value from another column called AppNbr based on that rows AppID column. The procedure is failing with a TOO_MANY_ROWS exception when it tries to SELECT a row. This is the PL/SQL:
DECLARE
lvnApplNbr NUMBER;
PROCEDURE deleteAppl(applId IN VARCHAR2) IS
BEGIN
BEGIN
SELECT ApplNbr -- Exception thrown here
INTO lvnApplNbr
FROM Appl
WHERE ApplID = applId;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
-- ... Delete it after some logic
END; -- End Procedure
BEGIN
...
deleteAppl('571E00BA-70E6-4523-BEAC-4568C3DD1A7D');
...
END;
The TOO_MANY_ROWS exception is thrown when it SELECT INTOs. I have no idea why it is throwing that error because if I just query this:
SELECT ApplNbr FROM Appl WHERE ApplId = '571E00BA-70E6-4523-BEAC-4568C3DD1A7D';
Only one row will come back with the correct ApplId.
What is going on?
Just use an alias for the related table (Appl):
PROCEDURE deleteAppl(applId IN VARCHAR2) IS
.....
.....
SELECT ApplNbr
INTO lvnApplNbr
FROM Appl a
WHERE a.ApplID = applId;
......
or change your parameter's name (applId) to another name such as i_applId :
PROCEDURE deleteAppl(i_applId IN VARCHAR2) IS
.....
.....
SELECT ApplNbr
INTO lvnApplNbr
FROM Appl
WHERE ApplID = i_applId;
......
Because in your case multiple matching perceived, if your parameter's name and column name are identical.

Oracle SQL procedure error I can't debug

I created the procedure below successfully, however when I run it, I get ORA-01422: exact fetch returns more than requested number of rows error.
Can anyone help in resolving my issue. Thanks
CREATE OR REPLACE PROCEDURE proc_create_new_user AUTHID CURRENT_USER IS
vc_username VARCHAR2(50);
vc_new_user VARCHAR2(100);
BEGIN
SELECT username
INTO vc_username FROM marketing;
FOR i IN 1..3 LOOP
vc_new_user:=
'CREATE USER '||vc_username||' IDENTIFIED BY password'||(i);
DBMS_OUTPUT.PUT_LINE('USER '||vc_new_user||' HAS BEEN CREATED');
EXECUTE IMMEDIATE vc_new_user;
END LOOP;
END proc_create_new_user;
/
EXECUTE proc_create_new_user;
error: ORA-01422: exact fetch returns more than requested number of rows
Your select is giving you more than one record which you are trying to hold in a variable that can hold only one value. Try using a WHERE clause in your select statement.
SELECT username
INTO vc_username FROM marketing
WHERE userid = '1234';

How to return multiple row by pl/sql stored function?

I search for this issue and finally I found a solution on this website but I get a strange error. I searched for the error but because I know very basic of pl/sql I was not able to solve it. here is my function which is trying to return name of the table:
CREATE OR REPLACE Function FF(BSB_NUMBER IN BANK.BSB#%TYPE) RETURN SYS_REFCURSOR
IS
C_RESULT SYS_REFCURSOR;
BEGIN
OPEN C_RESULT for
select * from bank where bank.bsb# = BSB_NUMBER;
return C_RESULT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Error ! There is no such account');
END FF;
/
AFTER i RUN=
Function created.
AFTER EXEC
SELECT * FROM TABLE(FF(012878));
ERROR:
ERROR at line 1:
ORA-22905: cannot access rows from a non-nested table item
Normally ref cursors are passed to client programs, such as JDBC Result Sets. However, it's easy enough to call a ref cursor in SQL:
select FF(012878) from dual;