Ref Cursor Type oracle - sql

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;

Related

How to check if row exists before SELECT INTO statement in Oracle 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;

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

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 procedure to update values of one table to another another table field

I have two tables with two attributes.I have written a procedure which should take valuesfrom table1 and update it in Table 2.
MEDICINE
BARCODE varchar2 13 byte
PDF_KUB_PATH varchar2 1000 byte
PARSED_ILAC_REHBERI
BARCODE varchar2 13 byte
PDF_KUB_PATH varchar2 1000 byte
This is my procedure in PL/SQL, i cant find where is my mistake, thanks in advance
CREATE OR REPLACE PROCEDURE Deneme
IS
BARCODETEMP VARCHAR2(13 BYTE);
S_KUB VARCHAR2 (1000 BYTE);
CURSOR c1 IS
SELECT a.PDF_KUB_PATH, a.BARCODE
FROM medicine b,parsed_ilac_rehberi a
WHERE a.BARCODE = b.barcode;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO S_KUB , BARCODETEMP,
EXIT WHEN c1%NOTFOUND;
UPDATE medicine
SET PDF_KUB_PATH = S_KUB
WHERE BARCODE = BARCODETEMP;
END LOOP;
CLOSE c1;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20001,'An error was encountered - '
||SQLCODE||' -ERROR'||SQLERRM);
end;
You dont need to use a procedure, you can solve your question just with sql script.
update medicine m
set m.PDF_KUB_PATH = (select p.PDF_KUB_PATH from parsed_ilac_rehberi p where m.BARCODE = p.BARCODE);
I think the warning/error is thrown when compiling on this line
FETCH c1 INTO S_KUB , BARCODETEMP,
It should be (ending with semi-colon and not comma)
FETCH c1 INTO S_KUB , BARCODETEMP;
You can avoid cursor and do this using MERGE
CREATE OR REPLACE PROCEDURE Deneme
IS
MERGE INTO medicine m
USING
(
SELECT a.PDF_KUB_PATH, a.BARCODE FROM parsed_ilac_rehberi a
) v
ON (m.BARCODE = v.BARCODE)
WHEN MATCHED THEN
UPDATE SET m.PDF_KUB_PATH = v.PDF_KUB_PATH
COMMIT;
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20001,'An error was encountered - '
||SQLCODE||' -ERROR'||SQLERRM);
END;
Shorter version (you don't need MERGE for 1 insert), you don't need redefine exception (as noted by Ben)
CREATE OR REPLACE PROCEDURE Deneme
IS
UPDATE (select a.PDF_KUB_PATH src, m.PDF_KUB_PATH dst
FROM medicine m INNER JOIN parsed_ilac_rehberi a
ON m.BARCODE = a.BARCODE)
SET dst = src;
END;

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;