How to execute 2 Store Procedures with conditions - oracle

I want to RUN SP2 inside SP1. The SP2 inserts several data into a table, one of those data is actual date.
So, i want that SP2 only execute if in the column date, the date is within the last 10 days.
It´s possible?
Thanks

Here's an example.
First, create a table and insert some sample rows:
SQL> create table my_tbl
2 (id number,
3 my_col date
4 );
Table created.
SQL> insert into my_tbl (id, my_col)
2 -- more than 10 days ago
3 select 1, date '2018-05-25' from dual union all
4 -- less than 10 days ago
5 select 2, date '2018-09-01' from dual;
2 rows created.
Create two procedures; SP_1 is supposed to call SP_2 if condition is met. I'm looping through both rows in the table; one row's date value is OK, another one isn't.
SQL> create or replace procedure sp_2 as
2 begin
3 dbms_output.put_line('...I am in SP_2 now');
4 end;
5 /
Procedure created.
SQL> create or replace procedure sp_1 as
2 begin
3 for cur_r in (select my_col from my_tbl order by id) loop
4 dbms_output.put_line('date value = ' || to_char(cur_r.my_col, 'yyyy-mm-dd'));
5 if cur_r.my_col >= trunc(sysdate) - 10 then
6 dbms_output.put_line('...calling SP_2');
7 sp_2;
8 else
9 dbms_output.put_line('...date condition failed - not calling SP_2');
10 end if;
11 end loop;
12 end;
13 /
Procedure created.
Testing:
SQL> set serveroutput on
SQL> begin
2 sp_1;
3 end;
4 /
date value = 2018-05-25
...date condition failed - not calling SP_2
date value = 2018-09-01
...calling SP_2
...I am in SP_2 now
PL/SQL procedure successfully completed.

Related

Checking of current system date in static table

I am new to pl/sql blocks..i have a requirement inside my proc as below:
I have a static data table tb_calender having column extract_date with DATE type. Want to check if the current system date is present in the table tb_calender.extract_date . If not present, exit the proc with logging error.
Please suggest on this.
A function might be more appropriate (so that you'd let the caller know whether today's date exists in the table or not). You could return a Boolean, or e.g. a number (which is simpler as you can use it in SQL, while Boolean works only in PL/SQL).
You probably don't want to check sysdate itself as it contains date AND time components (up to seconds), so ... how probable is it that table contains a value which matches right now? That's why I used TRUNC function.
Setup:
SQL> alter session set nls_date_Format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> select * from tb_calender;
EXTRACT_DATE
-------------------
10.01.2022 00:00:00 --> that's today's date
08.01.2022 00:00:00
SQL> select sysdate from dual;
SYSDATE
-------------------
10.01.2022 20:34:42
Function:
SQL> create or replace function f_test_01
2 return number
3 is
4 /* Return 1 if EXTRACT_DATE which is equal to today's date exists.
5 Return 0 otherwise
6 */
7 l_cnt number;
8 begin
9 select count(*)
10 into l_cnt
11 from tb_calender
12 where extract_date = trunc(sysdate);
13
14 return case when l_cnt = 0 then 0
15 else 1
16 end;
17 end f_test_01;
18 /
Function created.
SQL> select f_test_01 from dual;
F_TEST_01
----------
1
Procedure:
SQL> create or replace procedure p_test
2 is
3 l_cnt number;
4 begin
5 select count(*)
6 into l_cnt
7 from tb_calender
8 where extract_date = trunc(sysdate);
9
10 if l_cnt = 0 then
11 dbms_output.put_line('Today''s date does not exist');
12 else
13 dbms_output.put_line('Today''s date exists');
14 end if;
15 end;
16 /
Procedure created.
SQL> set serveroutput on
SQL> exec p_test;
Today's date exists
PL/SQL procedure successfully completed.
SQL>

Select Query in cursor FOR LOOP

Pretty new to Oracle, need help on this Procedure, using Oracle 11g
Sample table data (TAB1):
ID
Amount
Currency
10
300
GBP
15
500
GBP
20
100
GBP
Requirement is to select all the ID's from TAB1 based on currency and store it in a variable and later use these ID's in other select Queries within the same Stored Procedure.
CREATE OR REPLACE PROCEDURE myproc (i_id IN VARCHAR, i_curr IN VARCHAR)
AS
CURSOR GET_I IS
SELECT ID, CURRENCY
FROM TAB1
WHERE CURRENCY = 'GBP';
-- This will give me 3 ID's (10, 15 & 20) which I am storing in variable r_1 below.
r_1 VARCHAR (5) : NULL;
BEGIN
OPEN GET_I;
LOOP
FETCH GET_I INTO r_1;
IF GET_I%NOTFOUND
THEN
EXIT;
---In the below ELSE PART can we run a select query using the value stored in r_1??
--ELSE
--Data stored in r_1 to be used in further select queries in later part and output of the below
--be returned as SYS_REFCURSOR;
--BELOW two lines gives error
--FOR I in r_1 (
--SELECT ID FROM TAB2 WHERE TAB2.ID=r_1);
END IF;
END LOOP;
CLOSE GET_ID;
END;
It looks you want to use a nested FOR loop.
I'd suggest you to use cursor FOR loops - they are easier to maintain as you don't have to declare cursor variable (by the way, in your case it wouldn't work anyway as you'd like to store both ID and CURRENCY into a scalar R_1 variable), open the cursor, pay attention about exiting the loop and closing the cursor. In a cursor FOR loop, Oracle does all that for you.
Here's an example:
Sample table:
SQL> select * from tab1;
ID AMOUNT CUR
---------- ---------- ---
10 300 GBP
15 500 GBP
20 100 GBP
Procedure:
SQL> create or replace procedure myproc as
2 begin
3 for cur_id in (select id from tab1) loop
4 dbms_output.put_line('ID = ' || cur_id.id);
5 for cur_other in (select amount, currency
6 from tab1
7 where id = cur_id.id --> use ID fetched in outer loop
8 )
9 loop
10 dbms_output.put_line(cur_other.amount ||' - '|| cur_other.currency);
11 end loop;
12 end loop;
13 end;
14 /
Procedure created.
Testing:
SQL> set serveroutput on
SQL> exec myproc;
ID = 10
300 - GBP
ID = 15
500 - GBP
ID = 20
100 - GBP
PL/SQL procedure successfully completed.
SQL>
How to return a refcursor?
SQL> create or replace procedure myproc (par_id in tab1.id%type,
2 par_rc out sys_refcursor) as
3 begin
4 for cur_id in (select id
5 from tab1
6 where id = par_id
7 ) loop
8
9 open par_rc for select amount, currency
10 from tab1
11 where id = cur_id.id;
12 end loop;
13 end;
14 /
Procedure created.
SQL> var l_rc refcursor
SQL>
SQL> exec myproc(10, :l_rc);
PL/SQL procedure successfully completed.
SQL> print l_rc
AMOUNT CUR
---------- ---
300 GBP
SQL>

PLSQL trigger to raise application error not working

I'm trying to create a trigger which raise error if the total number of row exceeds 10, The plsql code was successfully compiled but it's not generating any error.
This is the plsql code:
SQL> CREATE OR REPLACE TRIGGER customer_count_check
2 BEFORE INSERT OR UPDATE ON customer2
3 FOR EACH ROW
4 DECLARE
5 count_customer NUMBER;
6 max_customer NUMBER := 10;
7 BEGIN
8 SELECT COUNT(*) INTO count_customer FROM customer2 WHERE cusid = :new.cusid;
9 IF count_customer >= max_customer THEN
10 RAISE_APPLICATION_ERROR (-20000,'Customer Table capacity exceeded');
11 END IF;
12 END;
13 /
i would say your trigger does't work as you expect, because your select statement inside return always one row.
you filter on a primary key!
that should work
SQL> CREATE OR REPLACE TRIGGER customer_count_check
2 BEFORE INSERT OR UPDATE ON customer2
3 FOR EACH ROW
4 DECLARE
5 count_customer NUMBER;
6 max_customer NUMBER := 10;
7 BEGIN
8 SELECT COUNT(*) INTO count_customer FROM customer2; --WHERE cusid = :new.cusid;
9 IF count_customer >= max_customer THEN
10 RAISE_APPLICATION_ERROR (-20000,'Customer Table capacity exceeded');
11 END IF;
12 END;
13 /

Oracle procedure (failure od date format)

I have this procedure:
SQL> create or replace procedure KORELACJA (START IN DATE, END IN DATE) AS
2 BEGIN
3 SELECT T.City, Corr(T.Value, H.Value)
4 FROM TEMP T
5 INNER JOIN HUMIDITY H
6 on T.City = H.City
7 and T.mDate = H.mDate
8 WHERE T.mDate between to_date(START,'YYYY-MM-DD') and to_date(END,'YYYY-MM-DD')
9 GROUP BY T.City
10 END;
11 /
with error: ORA-06550: line 1, column 7:
Anyone knows how to fix this problem?
[EDIT]
SQL> show error procedure KORELACJA;
Errors for PROCEDURE KORELACJA:
LINE/COL ERROR
-------- -----------------------------------------------------------------
4/1 PLS-00428: an INTO clause is expected in this SELECT statement
Have a look at this example; read comments within the code.
I've created sample tables, just to make sure that the procedure code compiles.
SQL> create table temp (city varchar2(10), value number, mdate date);
Table created.
SQL> create table humidity (city varchar2(10), value number, mdate date);
Table created.
The procedure itself:
SQL> create or replace procedure korelacja
2 (p_start in date, p_end in date) --> renamed parameters
3 is
4 l_city temp.city%type; --> declared local variables for SELECT
5 l_corr number; -- statement's results
6 begin
7 select t.city, corr(t.value, h.value)
8 into l_city, l_corr --> missing INTO clause
9 from temp t join humidity h on t.city = h.city
10 and t.mdate = h.mdate
11 where t.mdate between p_start and p_end --> parameters already are DATEs; you don't
12 group by t.city; -- need TO_DATE against them
13 end;
14 /
Procedure created.
SQL>

Oracle Delete Statement: how many rows have been deleted by cascade delete

I'm executing a statement like
DELETE FROM USER WHERE USER_ID=1;
In SQLDeveloper.
As the user is referenced in many tables (for example the user has an order, settings, ...) we activated ON DELETE CASCADE so that we do not have to delete each and every row manually. However while developing we are interested to know how many rows and and in which tables are "automatically" deleted by cascade delete.
Is there any way to find this out. Either by SQL-Statement, directly in sqldeveloper from a logfile or any other idea?
whilst this is not possible with sql%rowcount, it is possible if you write trigger code, but this means that you need a trigger on all tables you want to monitor. Also triggers would slow down operations a bit.
e.g.:
SQL> select * from one;
ID
----------
1
2
SQL> select * from child_of_one;
ID O_ID
---------- ----------
1 1
2 1
3 1
4 2
5 2
6 2
7 2
8 2
we want a package spec to hold an array of tables + counts:
SQL> create or replace package foo
2 as
3 type rowcount_tab is table of pls_integer index by varchar2(30);
4 t_rowcount rowcount_tab;
5 end foo;
6 /
Package created.
we want a trigger on the top level table to reset these counts to zero:
SQL> create or replace trigger one_biud
2 before insert or update or delete
3 on one
4 declare
5 begin
6 foo.t_rowcount.delete;
7 end;
8 /
Trigger created.
this assumes that you're only interested in the array with a delete from the top level table. if not, you'd want a trigger on each table with foo.t_rowcount.delete('TABLE_NAME') instead.
now a after for each row trigger on each table of interest to set the arrays:
SQL> create or replace trigger one_aiudfer
2 after insert or update or delete
3 on one
4 for each row
5 declare
6 begin
7 if (foo.t_rowcount.exists('ONE'))
8 then
9 foo.t_rowcount('ONE') := nvl(foo.t_rowcount('ONE'), 0)+1;
10 else
11 foo.t_rowcount('ONE') := 1;
12 end if;
13 end;
14 /
Trigger created.
SQL> create or replace trigger child_of_one_aiudfer
2 after insert or update or delete
3 on child_of_one
4 for each row
5 declare
6 begin
7 if (foo.t_rowcount.exists('CHILD_OF_ONE'))
8 then
9 foo.t_rowcount('CHILD_OF_ONE') := nvl(foo.t_rowcount('CHILD_OF_ONE'), 0)+1;
10 else
11 foo.t_rowcount('CHILD_OF_ONE') := 1;
12 end if;
13 end;
14 /
Trigger created.
now when we delete or whatever:
SQL> delete from one where id = 1;
1 row deleted.
SQL> declare
2 v_table varchar2(30);
3 begin
4 v_table := foo.t_rowcount.first;
5 loop
6 exit when v_table is null;
7 dbms_output.put_line(v_table || ' ' || foo.t_rowcount(v_table) || ' rows');
8 v_table := foo.t_rowcount.next(v_table);
9 end loop;
10 end;
11 /
CHILD_OF_ONE 3 rows
ONE 1 rows
PL/SQL procedure successfully completed.
SQL> delete from one where id = 2;
1 row deleted.
SQL> declare
2 v_table varchar2(30);
3 begin
4 v_table := foo.t_rowcount.first;
5 loop
6 exit when v_table is null;
7 dbms_output.put_line(v_table || ' ' || foo.t_rowcount(v_table) || ' rows');
8 v_table := foo.t_rowcount.next(v_table);
9 end loop;
10 end;
11 /
CHILD_OF_ONE 5 rows
ONE 1 rows

Resources