PLSQL Call Procedure If Exists Clause - sql

I'm using Oracle 9i.
Cue pseudo-code!
I have Stored Procedure A:
PROCEDURE stored_proc_a
IS
BEGIN
insert into...
END;
Then, I have Stored Procedure B:
PROCEDURE stored_proc_b
IS
BEGIN
stored_proc_a
WHERE NOT EXISTS (SELECT * FROM...);
END;
As you can see from my pseudo-code, I would like to call procedure A from procedure B, if a given row does not exist in a table.
I can't find any documentation that would suggest that the WHERE EXISTS clause can be used with a procedure call (the examples show its use with INSERT, UPDATE and DELETE).
Can I use WHERE EXISTS with a procedure call, and if not, what would be the correct code to do a procedure call based on the absence of a particular record in a table?

The correct way of doing this is the following:
PROCEDURE stored_proc_b
IS
num_rows number;
BEGIN
select COUNT(*) into num_rows
FROM my_table
WHERE my_table.xyz = 123; -- (whatever is appropriate)
if num_rows < 1
then
stored_proc_a;
end if;
END;
Figured this out thanks to Nicholas Krasnov and WBAR for their info on other posts.

Another way of achieving the same, in case you you want to call it for multiple rows and want to use data from Table in procedure B-
PROCEDURE stored_proc_b
IS
BEGIN
FOR rec IN (SELECT COL1 FROM <<TABLE1>> T1 WHERE NOT EXISTS (SELECT * FROM <<TABLE2>> T2...WHERE T1.JOIN_COL = T2.JOIN_COL))
LOOP
stored_proc_a;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
rollback;
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;

Procedure in Redshift Return "SELECT query has no destination for result data" Error

I keep getting the "SELECT query has no destination for result data" error upon calling this test procedure. What am I doing wrong? I did try adding the RETURN() command prior to SELECT statement but that didn't work either.
CREATE OR REPLACE PROCEDURE SchemaName.SP_Testing_Creating_Procedure (OUT ColumnName VARCHAR(9))
AS $$
BEGIN
SELECT TOP 10 ColumnName FROM SchemaName.TableName where ColumnName is not null;
END;
$$
LANGUAGE plpgsql;
CALL SchemaName.SP_Testing_Creating_Procedure();
As John mentioned you need to put the result into OUT column, examples of using IN, OUT and INOUT parameters you can find here
But if you need to return a few rows as a result, you have to use refcursor
as it's described here
CREATE OR REPLACE PROCEDURE SchemaName.SP_Testing_Creating_Procedure (INOUT result refcursor)
AS $$
BEGIN
OPEN result FOR
SELECT TOP 10 ColumnName
FROM SchemaName.TableName
WHERE ColumnName IS NOT null;
END;
$$
LANGUAGE plpgsql;
Then you can call the stored procedure in a transaction
BEGIN;
CALL logs.SP_Testing_Creating_Procedure('mycursor');
FETCH ALL FROM mycursor;
COMMIT;
another option is temp table which is also described in the above doc
Your procedure is running a SELECT command, but it is not doing anything with the results.
If your intention was to return a result set, you will need to put data in the OUT column.
See: Returning a result set - Amazon Redshift

How to output multiple rows from an existing table in a stored procedure using oracle sql developer?

I have an existing Customers table and want to output each row from this table using a stored procedure. There is no input criteria, just need to output all of the records.
The stored procedure should basically be equivalent to:
"SELECT C_ID, LAST, FIRST, DOB, DPHONE, EMAIL FROM customers;"
This seems simple but I can't figure it out. All my searches haven't worked out for this case.
How would one accomplish this?
EDIT: Answered my question below. Very simple.
In Oracle your options are:
1. Use a function and return a REF CURSOR
2. Use a procedure and use a REF CURSOR as an OUT parameter
3. Use a PIPELINED function
4. Use a function and return a collection.
read this documentation
Overview of Table Functions
see similar question here Return collection from packaged function for use in select
simple sample of such function
CREATE FUNCTION StockPivot(p refcur_pkg.refcur_t) RETURN TickerTypeSet
PIPELINED IS
out_rec TickerType := TickerType(NULL,NULL,NULL);
in_rec p%ROWTYPE;
BEGIN
LOOP
FETCH p INTO in_rec;
EXIT WHEN p%NOTFOUND;
-- first row
out_rec.ticker := in_rec.Ticker;
out_rec.PriceType := 'O';
out_rec.price := in_rec.OpenPrice;
PIPE ROW(out_rec);
-- second row
out_rec.PriceType := 'C';
out_rec.Price := in_rec.ClosePrice;
PIPE ROW(out_rec);
END LOOP;
CLOSE p;
RETURN;
END;
/
Nevermind! Just got it. It is pretty simple. I just did this:
CREATE OR REPLACE PROCEDURE CustomerReport AS
BEGIN
FOR cus IN (SELECT C_ID, LAST, FIRST, DOB, DPHONE, EMAIL FROM customers)
LOOP
dbms_output.put_line(cus.C_ID||' '||cus.FIRST||' '||cus.LAST||' '||cus.DOB||' '||cus.DPHONE||' '||cus.EMAIL);
END LOOP;
END;

Oracle delete procedure is not working correctly

This is my oracle stored procedure. I want to delete certain id when I pass data to procedure, but when I perform this proc. I get deleted everything that my trable has.
Can someone please check this out
CREATE OR REPLACE PROCEDURE Delete(
id IN number)
AS
BEGIN
DELETE FROM Users WHERE Users.id_user= id;
END;
/
I have tried to put :
DELETE FROM Users WHERE Users.id_user == id;
Then I get compilation error.
Have you tried DELETE FROM Users WHERE id_user = id; ?
Using == is not valid SQL for an equality check.
I still don't see why are you getting all rows deleted. DELETE FROM Users WHERE Users.id_user = id should be working properly.
More information on the DELETE STATEMENT syntax.
I have the same problem. When I pass an Id that doesn't exist in the table, everything gets deleted.
If the id exists in the table, then the procedure runs as I want it to run.
PROCEDURE tests
( jobnr IN varchar2,
x IN number,
menu in varchar2 default '1')
IS
counter number := 0;
BEGIN
delete from table_test where jobnr = jobnr;
if sql%notfound or sql%rowcount=0 then
rollback;
end if;
WHILE counter < x
LOOP
insert into table_test ( cskey, telnr, seq, jobnr, menu ) values ('Test'||counter, counter, counter, jobnr, menu );
counter := counter + 1;
END LOOP;
commit;
END;
Try this: Store input into local variable and then use this variable in your query. This worked for me.
CREATE OR REPLACE PROCEDURE Delete(
id IN number)
AS
v_id Number;
BEGIN
v_id := id;
DELETE FROM Users WHERE Users.id_user= v_id;
END;
CREATE TABLE USERS(ID NUMBER);
TABLE CREATED.
CREATE OR REPLACE PROCEDURE DeleteIDS(
id IN number)
AS
BEGIN
DELETE FROM Users WHERE id= id;
END;
/
PROCEDURE CREATED.
Here, in the table users id is there and also if you specify id in the declaration of procedure then that procedure deletes all the data.
so,
CREATE OR REPLACE PROCEDURE DeleteIDS(
idS IN number)
AS
BEGIN
DELETE FROM Users WHERE id= idS;
END;
/
PROCEDURE CREATED.
Now,
INSERT INTO USERS VALUES(10);
1 ROW INSERTED.
INSERT INTO USER VALUES(20);
1 ROW INSERTED.
COMMIT;
Now, execute the procedure
SQL>EXEC DELETEIDS(10);
PL/SQL PROGRAM SUCCESSFULLY COMPLETED.
SELECT * FROM USERS;
ID
---
2

trouble defining weakly defined ref cursor

I'm attempting to write a stored proc that takes in a number, n, and returns the first n results for a given query, exclusively locking those n rows. I'm a little new to SQL and I'm having a bit of difficulty matching data types correctly.
My package spec looks like this:
PACKAGE package IS
Type out_result_type is REF CURSOR;
PROCEDURE stored_proc
(in_n IN NUMBER DEFAULT 10,
out_list IN OUT out_result_type);
I then define the cursor in the procedure body, like so:
CURSOR OUT_RESULT_TYPE IS
SELECT a.id
FROM schema.table a
WHERE (some conditions) AND rownum <= in_n;
A bit later on I then try to extract the results of the cursor into the output variable:
OPEN OUT_RESULT_TYPE;
FETCH OUT_RESULT_TYPE INTO out_list; -- error on this line
CLOSE OUT_RESULT_TYPE;
But alas this code doesn't compile; oracle complains that out_list has already been defined with a conflicting data type. Any idea how I can resolve this issue? It's driving me crazy!
Thanks in advance.
CREATE OR REPLACE PACKAGE pkg_test
AS
TYPE tt_cur IS REF CURSOR;
PROCEDURE prc_cur (retval OUT tt_cur);
END;
CREATE OR REPLACE PACKAGE BODY pkg_test
AS
PROCEDURE prc_cur (retval OUT tt_cur)
AS
BEGIN
OPEN retval
FOR
SELECT *
FROM dual;
END;
END;
If you want to lock, use:
CREATE OR REPLACE PACKAGE BODY pkg_test
AS
PROCEDURE prc_cur (retval OUT tt_cur)
AS
BEGIN
OPEN retval
FOR
SELECT a.id
FROM schema.table a
WHERE (some conditions)
AND rownum <= in_n
ORDER BY
column
-- Never forget ORDER BY!
FOR UPDATE;
END;
END;
Two remarks:
A cursor doesn't lock.
You don't have to do Type out_result_type is REF CURSOR;, use default type sys_refcursor. See here: Oracle - How to have an out ref cursor parameter in a stored procedure?
Your out_list must be of wrong type. Consider (script run on 10.2.0.3):
CREATE TABLE t AS SELECT ROWNUM ID FROM all_objects WHERE ROWNUM <= 100;
CREATE OR REPLACE PACKAGE cursor_pck AS
TYPE out_result_type is REF CURSOR;
PROCEDURE stored_proc (p_in IN NUMBER DEFAULT 10,
p_out_list IN OUT out_result_type);
END cursor_pck;
/
If you want to select and lock the rows at the same time you would use the FOR UPDATE clause:
CREATE OR REPLACE PACKAGE BODY cursor_pck AS
PROCEDURE stored_proc (p_in IN NUMBER DEFAULT 10,
p_out_list IN OUT out_result_type) IS
BEGIN
OPEN p_out_list FOR SELECT a.id FROM t a WHERE ROWNUM <= p_in FOR UPDATE;
END stored_proc;
END cursor_pck;
/
With the following setup, you will call the procedure like this:
SQL> SET SERVEROUTPUT ON;
SQL> DECLARE
2 l_cursor cursor_pck.out_result_type;
3 l_id t.id%TYPE;
4 BEGIN
5 cursor_pck.stored_proc(3, l_cursor);
6 LOOP
7 FETCH l_cursor INTO l_id;
8 EXIT WHEN l_cursor%NOTFOUND;
9 dbms_output.put_line(l_id);
10 END LOOP;
11 END;
12 /
1
2
3
PL/SQL procedure successfully completed
This is not going to work the way it's written, because
out_list expects a cursor, not a cursor result.
The name out_result_type is already used for a type, so you can't redefine it to be a cursor in the same scope.
Oracle provides a pre-defined weak reference cursor: sys_refcursor. In usage it would look like:
CREATE OR REPLACE PACKAGE pkg_test
AS
PROCEDURE prc_cur (p_retval OUT sys_refcursor,
p_lookup IN VARCHAR2);
END pkg_test;
CREATE OR REPLACE PACKAGE BODY pkg_test
AS
PROCEDURE prc_cur(p_retval OUT sys_refcursor
p_lookup IN VARCHAR2)
IS
BEGIN
OPEN retval FOR SELECT a.value
FROM tblname a
WHERE a.id <= p_lookup;
END prc_cur;
END pkg_test;
This saves you the trouble of needing to declare a type. The sys_refcursor is a pointer to a result set from an open cursor. If you are familiar with Java, it's the same concept as the java.sql.ResultSet object which provides a way to get at the results of a query.