How to check if row exists before SELECT INTO statement in Oracle SQL - sql

I'm using Oracle SQL and have a procedure that is doing some operations on tables. During the procedure there is a "SELECT x INTO y FROM TABLE z WHERE..." statement inside a loop. Unfortunatly during the procedure I can't guarante that there is always a row to the corresponding where condition because it changes dynamically.
Is it possible to check if a row exists before the statement? I was thinking of sth like "if exists(select ...) then SELECT X INTO y..."
Thanks for the help!
Jack

Well, there's no point in checking it first, and re-using the same statement again.
You could handle the exception (possibly in an inner BEGIN-EXCEPTION-END block):
declare
y number;
begin
begin --> inner block starts here
select x into y from z where ...
insert into ...
exception
-- handle it, somehow; I chose not to do anything
when no_data_found then
null;
end; --> inner block ends here
end;
Or, if you used cursor FOR loop, you wouldn't have to handle it because - if select returns x, insert would run. Otherwise, nothing in that loop would ever be executed:
begin
for cur_r in (select x from z where ...) loop
insert into ...
end loop;
end;

An exception handler as in Littlefoot's answer is the most correct and explicit approach, however just for completeness you might also consider using an aggregate.
Value 'X' exists in the table:
declare
p_someparam varchar2(1) := 'X';
l_somevalue varchar2(1);
l_check number;
begin
select max(dummy), count(*) into l_somevalue, l_check
from dual d
where d.dummy = p_someparam;
dbms_output.put_line('Result: '||l_somevalue);
dbms_output.put_line(l_check||' row(s) found');
end;
Result: X
1 row(s) found
Value 'Z' does not exist in the table:
declare
p_someparam varchar2(1) := 'Z';
l_somevalue varchar2(1);
l_check number;
begin
select max(dummy), count(*) into l_somevalue, l_check
from dual d
where d.dummy = p_someparam;
dbms_output.put_line('Result: '||l_somevalue);
dbms_output.put_line(l_check||' row(s) found');
end;
Result:
0 row(s) found
You can add logic to handle the cases where the count check is 0 or greater than 1.

If you are having procedure then I should say use if statement and then write the sql:
select some_column into some_variable from tablename where condition
IF somevariable not in (<list of values separated by comma>)THEN
{statements to execute }
END IF;

Related

oracle sql if condition then select statement1 else select statement2

I have parameter :prmtr and what I wanted is to use a select statement based on the parameter input.
I tried this:
if :prmtr= 'A' then
select * from tblA;
else
select * from tblB;
end if;
But it wont work.
Is there some other way to do this?
You may try something like this with a CURSOR variable and PRINT command. This works in SQL* plus and in SQL developer or TOAD when run as script.
VARIABLE prmtr VARCHAR2
EXEC :PRMTR := 'A' -- SET values of parameter
VARIABLE x refcursor -- a cursor variable
DECLARE
BEGIN
IF :PRMTR = 'A' THEN
OPEN :x FOR
SELECT *
FROM employees;
ELSE
OPEN :x FOR
SELECT *
FROM departments;
END IF;
END;
/
PRINT x -- gives you the result of the query.

Using Cursor in oracle SQL

I want to perform the delete operation in 2 tables with a given id here is sudo code
declare
cursor del_id is
select person_id from table_1 where termination is true
begin
for id_x in del_id
delete from table_X where id=id_x
delete from tabele_Y where id=id_x
How to do that ? i can't directly use my cursor please help.
I just try to print my id
begin
for id in del_id
LOOP
dbms_output.put_line(id);
END LOOP;
end;
Getting this error
Error report -
ORA-06550: line 11, column 3:
PLS-00306: wrong number or types of arguments in call to 'PUT_LINE'
To print the values from a cursor, you need to explicitly write the columns you want; dbms_output.put_line can not handle a row that may contain many columns with different types, so you need to pass it a string.
SQL> declare
2 cursor del_id is select 1 as one, 2 as two from dual;
3 begin
4 FOR id IN del_id
5 LOOP
6 dbms_output.put_line(id.one || ' - ' || id.two);
7 END LOOP;
8 end;
9 /
1 - 2
PL/SQL procedure successfully completed.
If you need to use the values from a cursor in some statement, a DELETE in your question, you need to do the same, by explicitly writing the column name; for example:
declare
cursor del_id is select 1 as one, 2 as two from dual;
begin
FOR id IN del_id
LOOP
delete from someTable where someColumn = id.one;
END LOOP;
end;
You do not need a cursor:
BEGIN
DELETE FROM table_X
WHERE id IN ( select person_id from table_1 where termination is true );
DELETE FROM table_Y
WHERE id IN ( select person_id from table_1 where termination is true );
END;
/
You could also use a collection:
CREATE TYPE id_type IS TABLE OF INTEGER;
/
DECLARE
ids id_type;
BEGIN
SELECT person_id
BULK COLLECT INTO ids
FROM table_1
WHERE termination is true;
DELETE FROM table_X
WHERE id MEMBER OF ids;
DELETE FROM table_Y
WHERE id MEMBER OF ids;
END;
/

PLSQL oracle select after declare ORA-06550 PLS-00103

Using PL/SQL Developer client.
Oracle throws me ORA-065550 PLS-00103 Encountered the symbol "SELECT".
Well, can not find what's wrong here.
DECLARE someId NUMBER;
BEGIN
select id into someId from someTable where someColumn = 'someUniqueValue';
select * from someTable; --here
END;
select * from someTable; --or here
Neither second select, neither third works. When I dmbs_output someId into console it works well, this assigning to declared variable. But why I can not just select after 'into'? I want to declare one time value, and then make
select * from someTable where id = someId
or to be precised want to make like thousand inserts and I want to cache that first select.
DECLARE someId NUMBER;
BEGIN
select id into someId from someTable where someColumn = 'someValue';
END;
/
select * from otherTable where otherTableId = someId;
Here I lost someId scope I guess.
Basically you doing a lot of mistakes while doing this code.
1.You cant just 'SELECT *' in the anonymous block. You need to have cursor to do it.
2.Your variable scope is till the anonymous block. Now you are trying to access the variable outside the block --> NAAH not possible.
So I have tried to resolve your issue by below snippet hope it helps.
DECLARE
someId NUMBER;
p_lst sys_refcursor;
BEGIN
SELECT id INTO someId FROM someTable WHERE someColumn = 'someUniqueValue';
OPEN p_lst FOR
'SELECT * FROM someTable
where otherTableId = '||someId;
END;
Assuming you're coding a sql script, you can
1) declare your variable
2) populate it in an anonymous pl/sql block
3) use it elsewhere
--1
variable my_num number
--2
begin
select 1 into :my_num from dual;
end;
/
--3
select :my_num from dual;
That you can achieve through using SQL*Plus
SQL> variable id number
SQL> begin
select 1000 into :id from dual;
end;
/
SQL> print id
ID
----------
1000
SQL> SELECT * FROM tbl_a WHERE id = :id
In Oracle doesn't let you implicitly return the result of a query. The result always has to be explicitly returned in some fashion. The simplest way is to use DBMS_OUTPUT (roughly equivalent to print) to output the variable:
DECLARE
myname varchar2(20);
BEGIN
myname := 'Tom';
dbms_output.print_line(myname);
END;
This isn't terribly helpful if you're trying to return a result set, however. In that case, you'll either want to return a collection or a refcursor. However, using either of those solutions would require wrapping your code in a function or procedure and running the function/procedure from something that's capable of consuming the results. A function that worked in this way might look something like this:
CREATE FUNCTION my_function (myname in varchar2)
my_refcursor out sys_refcursor
BEGIN
open my_refcursor for
SELECT *
FROM Customers
WHERE Name = myname;
return my_refcursor;
END my_function;

How to set a default value for a query that returns no rows?

I have created a trigger with a select statement and I want to say if this select statement does not return any rows then put a 0 in the variable "auxiliar". I tried to use NVL(auxiliar,0) but it does not work. How can I do this?
SELECT NVL(salary,0) INTO auxiliar FROM BILL WHERE code=:NEW.code;
[UPDATED] My trigger code:
IF preCondicio THEN
KMpendents:=coalesce(SELECT rev_pendent_km
INTO KMpendents
FROM REV_PENDENT
WHERE rev_pendent_vehicle_codi=:NEW.lloguer_vehicle_codi,0);
IF KMtotals+KMpendents>=15000 THEN
SELECT venedor_codi
INTO venedorCodi
FROM venedor
WHERE venedor_alta=(
SELECT MAX(venedor_alta)
FROM venedor
WHERE venedor_delegacio_codi=(
SELECT venedor_delegacio_codi
FROM venedor
WHERE venedor_codi=:NEW.lloguer_venedor_codi));
INSERT INTO REVISIONS VALUES(:NEW.lloguer_vehicle_codi,:NEW.lloguer_dataf,KMtotals+KMpendents,venedorCodi);
IF KMpendents!=0 THEN
DELETE FROM REV_PENDENT
WHERE rev_pendent_vehicle_codi=:NEW.lloguer_vehicle_codi;
END IF;
ELSE
IF KMpendents!=0 THEN
UPDATE REV_PENDENT SET rev_pendent_km=KMtotals+KMpendents WHERE rev_pendent_vehicle_codi=:NEW.lloguer_vehicle_codi;
ELSE INSERT INTO REV_PENDENT VALUES(:NEW.lloguer_vehicle_codi,KMtotals,:NEW.lloguer_dataf);
END IF;
END IF;
END IF;
The variable KMpendents is equivalent to the variable auxiliar which I told before the updated. But Oracle shows me these errors:
PLS-00103: Encountered the symbol "," when expecting one of the
following: . ( * # % & - + ; / at for mod remainder rem and or group
having intersect minus order start union where connect || indicator
multiset
If the select clause contains only aggregate functions then there will always be at least one row returned.
SELECT coalesce(sum(salary),0)
INTO auxiliar
FROM BILL
WHERE code=:NEW.code;
BEGIN
SELECT NVL(salary,0) INTO auxiliar FROM BILL WHERE code=:NEW.code;
EXCEPTION
WHEN NOTFOUND THEN
auxiliar := 0;
END;
Or you can use SQL%NOTFOUND too to check if the statement returned no rows.
CREATE or REPLACE TRIGGER trigger_name
BEFORE INSERT
ON table_name
[ FOR EACH ROW ]
DECLARE
-- variable declarations
BEGIN
....
....
BEGIN
SELECT NVL(salary,0) INTO auxiliar FROM BILL WHERE code=:NEW.code;
EXCEPTION
WHEN NOTFOUND THEN
auxiliar := 0;
END;
--Yes, this is possible and valid.
EXCEPTION
WHEN ...
-- exception handling
END;

Ref Cursor Type oracle

I would like to check if cursor have only one row.
and return this,
--Please see my question inside the procedure?
CREATE OR REPLACE PROCEDURE GetInterestRate( p_id IN NUMBER DEFAULT NULL,
RC1 IN OUT SYS_REFCURSOR
)
....
begin
open rc1 for select * from interestRatesTable i join parametersInterest p on
i.interestName = p.Name
where i.idinterest = p_id
and p.Active ='A';
-- I would like to check if cursor have only one row.
--- if it has zero row, no result I got to raise an error
--- if it has more than one row, I got to raise to many interest rates!
-- how can I do this?
end;
Oracle will raise the errors for you, simply select a value into a row
I guess you should really catch the exception in an exception block too.
CREATE OR REPLACE PROCEDURE GetInterestRate( p_id IN NUMBER DEFAULT NULL,
RC1 IN OUT SYS_REFCURSOR
)
....
begin
select 1
into a_value
from interestRatesTable i
join parametersInterest p ...
open rc1 for ......
EXCEPTION
WHEN NO_DATA_FOUND THEN
.....
WHEN TOO_MANY_ROWS THEN
.....
WHEN OTHERS THEN
.....
end;
I think you'll have to run the query first before opening the cursor.
CREATE OR REPLACE PROCEDURE ...
begin
select count(*)
into row_found
from interestRatesTable i join parametersInterest p ...
and rownum = 1;
if row_found = 0 then raise ...
end if
open ...
end;