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
Related
I am not able to get the value of variable v when I fire this trigger on my table:
create or replace trigger tri
after insert or update or delete on site_sector
declare
v number;
begin
if inserting then
v:=sql%rowcount;
dbms_output.put_line('There is :'||v||' row affected');
elsif updating then
v:=sql%rowcount;
dbms_output.put_line('There is :'||v||' row affected');
elsif deleting then
v:=sql%rowcount;
dbms_output.put_line('There is :'||v||' row affected');
else
dbms_output.put_line('There is no row affected');
end if;
end;
Well, that won't work; something like this might.
Sample table:
SQL> desc test
Name Null? Type
----------------------------------------------------- -------- -----------------
ID NUMBER
Compound trigger: declare a variable which will be incremented in BEFORE EACH ROW; number of rows affected is then displayed in AFTER STATEMENT.
SQL> create or replace trigger tri
2 for insert or update or delete on test
3 compound trigger
4
5 g_cnt number := 0;
6
7 before each row is
8 begin
9 g_cnt := g_cnt + 1;
10 end before each row;
11
12 after statement is
13 begin
14 dbms_output.put_line('Number of rows affected = ' || g_cnt);
15 end after statement;
16 end;
17 /
Trigger created.
Testing:
SQL> insert into test (id)
2 select level from dual connect by level <= 5;
Number of rows affected = 5
5 rows created.
SQL> update test set id = id + 10 where id <= 3;
Number of rows affected = 3
3 rows updated.
SQL> delete from test where id < 10;
Number of rows affected = 2
2 rows deleted.
SQL>
Messages "match"; that's why I wonder where you'll be using this, as Oracle shows that info anyway.
There is a requirement from client side that after function get executed more than 2 times then its output should be concatinated with some string and this function is inside a package .
for example...
function get called 7 times from package (its a backend job which executed automatically) and returns 'abc' but when the job runs for the 3rd time i want output 'abcde'.
One option is to create a separate log table and insert a row for each of function calls; then - within a function - check how many times it was invoked and return appropriate output. Something like this:
Log table:
SQL> CREATE TABLE flog
2 (
3 cuser VARCHAR2 (30),
4 sid NUMBER
5 );
Table created.
Package:
SQL> CREATE OR REPLACE PACKAGE pkg_test
2 IS
3 FUNCTION f_test
4 RETURN VARCHAR2;
5
6 PROCEDURE p_test;
7 END;
8 /
Package created.
Package body:
SQL> CREATE OR REPLACE PACKAGE BODY pkg_test
2 IS
3 FUNCTION f_test
4 RETURN VARCHAR2
5 IS
6 l_cnt NUMBER;
7 retval VARCHAR2 (10);
8 BEGIN
9 SELECT COUNT (*)
10 INTO l_cnt
11 FROM flog
12 WHERE cuser = USER
13 AND sid = SYS_CONTEXT ('USERENV', 'SID');
14
15 retval := CASE WHEN l_cnt <= 2 THEN 'abc' ELSE 'abc' || 'de' END;
16 RETURN retval;
17 END;
18
19 PROCEDURE p_test
20 IS
21 BEGIN
22 FOR i IN 1 .. 3
23 LOOP
24 INSERT INTO flog (cuser, sid)
25 VALUES (USER, SYS_CONTEXT ('USERENV', 'SID'));
26
27 DBMS_OUTPUT.put_line ('Execution #' || i || ', result = ' || f_test);
28 END LOOP;
29 END;
30 END pkg_test;
31 /
Package body created.
Testing:
SQL> SET SERVEROUTPUT ON
SQL> EXEC pkg_test.p_test;
Execution #1, result = abc
Execution #2, result = abc
Execution #3, result = abcde
PL/SQL procedure successfully completed.
SQL>
STEP 1:
Creating a new table and adding a record to the database with the help of the procedure
• the function will take 3 parameters string ,string and number,
• The first parameter represents the name of the table, and the other two parameters represent the records to be added to the created table.
Step 2:
As seen in the screenshot below; As described above, when the function runs, a table named 'mytable' will be created in the database with the first parameter, and other parameters will be added to the created table as a record.
enter image description here
Why function? They are supposed to return some value, not to perform DDL. Therefore, a procedure it is, using dynamic SQL as otherwise it won't work.
SQL> CREATE OR REPLACE PROCEDURE p_test (par_table_name IN VARCHAR2,
2 par_str IN VARCHAR2,
3 par_num IN NUMBER)
4 IS
5 l_cnt NUMBER;
6 BEGIN
7 SELECT COUNT (*)
8 INTO l_cnt
9 FROM user_tables
10 WHERE UPPER (table_name) = UPPER (par_table_name);
11
12 IF l_cnt = 0
13 THEN
14 EXECUTE IMMEDIATE 'create table '
15 || par_table_name
16 || ' as select '
17 || DBMS_ASSERT.enquote_literal (par_str)
18 || ' col_string, '
19 || par_num
20 || ' col_number from dual';
21 ELSE
22 raise_application_error (-20000,
23 'Object with that name already exists');
24 END IF;
25 END;
26 /
Procedure created.
Testing:
SQL> exec p_test('little', 'foot', 20);
PL/SQL procedure successfully completed.
SQL> select * from little;
COL_ COL_NUMBER
---- ----------
foot 20
SQL>
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 /
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.