How to use this trigger on table? - oracle

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.

Related

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 /

How to execute 2 Store Procedures with conditions

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.

How can I change before update trigger to before insert trigger?

I have a table and this table must have at most 1000 row. When user wants to add 1001st row, there must be an error. I know i should use insert trigger. I'm a new person in SQL can you help me?
My code is:
create or replace trigger update_ext_app_serv
before update on EXTERNAL_APP_SERVICE
for each row
declare
row_count number;
old_service_id number;
new_service_trigger varchar(30);
old_service_trigger varchar(30);
begin
row_count := 0;
new_service_trigger := :NEW.TRIGGER_NAME;
old_service_trigger := :OLD.TRIGGER_NAME;
old_service_id := :OLD.SERVICE_ID;
select count(*) into row_count
from EXTERNAL_APP_PROFILE
where ORIG_ID = old_service_id
or TERM_FAILURE_RESP_ID = old_service_id
or TERM_ID = old_service_id;
if (row_count > 0) and (new_service_trigger not like old_service_trigger)
then
raise_application_error(-20706, 'Unable to update Trigger. The service is referenced at least External Application Profile.');
end if;
end;
The way to do this is with an AFTER trigger, and at the statement rather than row level.
SQL> create or replace trigger t1000_trg
2 after insert on t1000
3 declare
4 n pls_integer;
5 begin
6 select count(*) into n
7 from t1000;
8 if n > 1000 then
9 raise_application_error(-20999, 'No more than 1000 records!');
10 end if;
11 end;
12 /
Trigger created.
SQL>
Here's our test data.
SQL> select count(*) from t1000;
COUNT(*)
----------
999
SQL>
1000th record okay...
SQL> insert into t1000 values (1000);
1 row created.
SQL>
... but 1001st record is rejected:
SQL> insert into t1000 values (1001);
insert into t1000 values (1001)
*
ERROR at line 1:
ORA-20999: No more than 1000 records!
ORA-06512: at "FOX.T1000_TRG", line 7
ORA-04088: error during execution of trigger 'FOX.T1000_TRG'
SQL>
Works for multi-row insert statements too.
SQL> roll
Rollback complete.
SQL> select count(*) from t1000;
COUNT(*)
----------
999
SQL> insert into t1000 select 1000 + level from dual connect by level <= 5;
insert into t1000 select 1000 + level from dual connect by level <= 5
*
ERROR at line 1:
ORA-20999: No more than 1000 records!
ORA-06512: at "FOX.T1000_TRG", line 7
ORA-04088: error during execution of trigger 'FOX.T1000_TRG'
SQL>

ORACLE SQL%ROWCOUNT doesn't work inside a cursor fetch

In my following code, I'm unable to get the inserted row count within a cursor fetch.
...
row_count NUMBER:= 0;
BEGIN
OPEN object_id_cur(id, c_bool);
LOOP
FETCH object_id_cur INTO l_object_id;
EXIT WHEN object_id_cur%NOTFOUND;
INSERT INTO table1(
id,
num
)
SELECT t2.r_object_id,
t2.num
FROM table2
WHERE t2.r_object_id = l_object_id.r_object_id;
row_count:= row_count + SQL%ROWCOUNT;
-- I also tried dbms_output.put_line(SQL%ROWCOUNT);
END LOOP;
CLOSE object_id_cur;
COMMIT;
dbms_output.put_line('insert count= ' || row_count || ' rows inserted...');
END;
My obtained result is: count = rows inserted... count is blank. If I move the insert outside the cursor fetch, then the row count works just fine. Is there a logical explanation for this? Thanks!
count is a reserved keyword. Use "count" or some other identifer say cnt. Also, add the missing semicolon at then end of the increment statement.
declare
cnt number := 0;
begin
. . .
cnt := cnt + SQL%ROWCOUNT;
. . .
Demo:
SQL> create table t (id int);
Table created.
SQL> declare
2 cursor c is
3 select level n from dual connect by level <= 100; -- produces 100 rows
4 n int;
5 cnt number := 0;
6 begin
7 open c;
8 loop
9 fetch c into n;
10 exit when c%notfound;
11 insert into t (id)
12 select n from dual union all
13 select n from dual; -- insert each value twice
14 cnt := cnt + sql%rowcount;
15 end loop;
16 close c;
17 dbms_output.put_line(cnt); -- should be 200
18 end;
19 /
200 -- correct output
PL/SQL procedure successfully completed.
SQL>
As you can see above, the SQL%rowcount works correctly. It could be that your below select query is not producing any rows.
SELECT t2.r_object_id,
t2.num
FROM table2
WHERE t2.r_object_id = l_object_id.r_object_id;
SQL%ROWCOUNT return the number of rows fetched/processed by the last DML executed. If the DML fails after fetching 1 row, due to any reason, SQL%ROWCOUNT will return only 1, the number of rows fetched/processed so far. It wont give you the total count. I did a simple PLSQL block and getting the SQL%ROWCOUNT working fine. Seems there is something else which is not working in your code.
declare
num number := 0;
begin
for i in 1 .. 10
loop
insert into a_table (id)
values (i);
num := num + sql%rowcount;
end loop;
dbms_output.put_line (num);
end;

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