[英]ORACLE PL/SQL: my SELECT COUNT statement isn't working for triggers
因此,我想創建一個觸發器,如果表中的記錄數已超過16,則會觸發錯誤消息。 我嘗試使用以下代碼,但沒有任何反應,在16點之后仍可以插入更多記錄。
create or replace trigger trg_ins_jim before insert on JIM for each row
declare
v_id_end RESULTS.id%type;
v_prices RESULTS.PRICE%type;
v_count NUMBER(20);
begin
v_prices := :new.age + :new.price;
SELECT COUNT(*) INTO v_count FROM JIM;
IF INSERTING AND v_count<=16 THEN
insert into RESULTS(ID,PRICE) values(:NEW.ID,v_prices);
ELSIF v_count>16 THEN
Raise_Application_Error (-20343, 'Too many records');
END IF;
end;
我認為select語句的設置方式存在問題,因為當我將v_count更改為:new.ID只是為了檢查是否仍然存在相同的問題時,如果ID編號大於16,我將收到一條錯誤消息
這不是觸發器適合的問題。 讓我們觀察一下各種DML觸發器會發生什么。
create table jim (id number, age number, price number);
create table results (id number, price number);
--------------------------------------------------------------
create or replace trigger trg_ins_jim_bir --Before insert row
before insert on jim
for each row
declare
v_id_end results.id%type;
v_prices results.price%type;
v_count number(20);
begin
v_prices := :new.age + :new.price;
select count(*) into v_count from jim;
if v_count<=16 then
insert into results(id,price) values(:new.id,v_prices);
else
raise_application_error (-20343, 'Too many records');
end if;
end;
/
alter trigger trg_ins_jim_bir disable;
/
--------------------------------------------------------------
create or replace trigger trg_ins_jim_birat --Before insert row autonomous transaction
before insert on jim
for each row
declare
PRAGMA AUTONOMOUS_TRANSACTION;
v_prices results.price%type;
v_count number(20);
begin
v_prices := :new.age + :new.price;
select count(*) into v_count from jim;
if v_count<=16 then
insert into results(id,price) values(:new.id,v_prices);
commit;
else
raise_application_error (-20344, 'Too many records');
end if;
end;
/
alter trigger trg_ins_jim_birat disable;
/
--------------------------------------------------------------
create or replace trigger trg_ins_jim_air --After insert row
after insert on jim
for each row
declare
v_id_end results.id%type;
v_prices results.price%type;
v_count number(20);
begin
v_prices := :new.age + :new.price;
select count(*) into v_count from jim;
if v_count<=16 then
insert into results(id,price) values(:new.id,v_prices);
else
raise_application_error (-20345, 'Too many records');
end if;
end;
/
alter trigger trg_ins_jim_air disable;
/
--------------------------------------------------------------
create or replace trigger trg_ins_jim_airat --After insert row autonomous transaction
after insert on jim
for each row
declare
PRAGMA AUTONOMOUS_TRANSACTION;
v_prices results.price%type;
v_count number(20);
begin
v_prices := :new.age + :new.price;
select count(*) into v_count from jim;
if v_count<=16 then
insert into results(id,price) values(:new.id,v_prices);
commit;
else
raise_application_error (-20346, 'Too many records');
end if;
end;
/
alter trigger trg_ins_jim_airat disable;
/
--------------------------------------------------------------
create or replace trigger trg_ins_jim_ais -- After insert statement
after insert on jim
declare
v_count number(20);
begin
select count(*) into v_count from jim;
if v_count>16 then
raise_application_error (-20347, 'Too many records');
end if;
end;
/
alter trigger trg_ins_jim_ais disable;
/
--------------------------------------------------------------
-- Following run in sqldeveloper
alter trigger trg_ins_jim_bir enable;
insert into jim (id, age, price)
select level, trunc(dbms_random.value(10,30)), round(50*dbms_random.value,2)
from dual connect by level < 15;
/*
insert into jim (id, age, price)
select level, trunc(dbms_random.value(10,30)), round(50*dbms_random.value,2)
from dual connect by level < 15
Error report -
ORA-04091: table BOB.JIM is mutating, trigger/function may not see it
ORA-06512: at "BOB.TRG_INS_JIM_BIR", line 7
ORA-04088: error during execution of trigger 'BOB.TRG_INS_JIM_BIR'
This is because a row level trigger CONNOT refer to the table that caused it to fire.
*/
select 'Jim', count(*) cnt from jim
union all
select 'Results', count(*) from results;
/*
Jim 0
Results 0
OK Nothing inserted.
*/
alter trigger trg_ins_jim_bir disable;
alter trigger trg_ins_jim_air enable;
insert into jim (id, age, price)
select level, trunc(dbms_random.value(10,30)), round(50*dbms_random.value,2)
from dual connect by level < 15;
/*
insert into jim (id, age, price)
select level, trunc(dbms_random.value(10,30)), round(50*dbms_random.value,2)
from dual connect by level < 15
Error report -
ORA-04091: table BOB.JIM is mutating, trigger/function may not see it
ORA-06512: at "BOB.TRG_INS_JIM_AIR", line 7
ORA-04088: error during execution of trigger 'BOB.TRG_INS_JIM_AIR'
Same result a row level trigger CONNOT refer to the table that caused it to fire
*/
--- How about an AUTONOMOUS_TRANSACTION;
alter trigger trg_ins_jim_air disable;
alter trigger trg_ins_jim_birat enable;
insert into jim (id, age, price)
select level, trunc(dbms_random.value(10,30)), round(50*dbms_random.value,2)
from dual connect by level < 15;
-- 14 rows inserted
select 'Jim', count(*) cnt from jim
union all
select 'Results', count(*) from results;
/*
Jim 14
Results 14
(looks promising) so continue
*/
commit ;
insert into jim (id, age, price)
select level, trunc(dbms_random.value(10,30)), round(50*dbms_random.value,2)
from dual connect by level < 15;
-- 14 rows inserted
select 'Jim', count(*) cnt from jim
union all
select 'Results', count(*) from results;
/*
Jim 28
Results 28
NO that allows 28 rows in table.
Well not because the trigger isn't working but because it's an AUTONOMOUS TRANSACTION. (which cannot see the rows processed outside of it)
But is it because we used a BEFORE Trigger?
*/
rollback ;
select 'Jim', count(*) cnt from jim
union all
select 'Results', count(*) from results;
/*
Jim 14
Results 28
HOW? The rollback above rolls back the second set of rows in jim, but NOT results as they were committed
during to the requirements of AUTONOMOUS TRANSACTION.
*/
delete from jim;
delete from results;
insert into jim (id, age, price)
select level, trunc(dbms_random.value(10,30)), round(50*dbms_random.value,2)
from dual connect by level < 15;
-- 14 rows inserted
commit ;
alter trigger trg_ins_jim_birat disable;
alter trigger trg_ins_jim_airat enable;
select 'Jim', count(*) cnt from jim
union all
select 'Results', count(*) from results;
/*
Jim 14
Results 14
*/
insert into jim (id, age, price)
select level, trunc(dbms_random.value(10,30)), round(50*dbms_random.value,2)
from dual connect by level < 15;
-- 14 rows inserted
select 'Jim' tbl, count(*) cnt from jim
union all
select 'Results', count(*) from results;
/*
Jim 28
Results 28
Same results for after trigger as before with AUTONOMOUS TRANSACTION.
*/
rollback;
select 'Jim' tbl, count(*) cnt from jim
union all
select 'Results', count(*) from results;
/*
Jim 14
Results 28
And same results after rollback;
*/
delete from jim;
delete from results;
commit ;
alter trigger trg_ins_jim_airat disable;
alter trigger trg_ins_jim_ais enable;
insert into jim (id, age, price)
select level, trunc(dbms_random.value(10,30)), round(50*dbms_random.value,2)
from dual connect by level < 15;
-- 14 rows inserted
select 'Jim' tbl, count(*) cnt from jim
union all
select 'Results', count(*) from results;
/*
Jim 14
Results 0
OOPS: Nothing in results.
*/
rollback;
alter trigger trg_ins_jim_airat enable;
insert into jim (id, age, price)
select level, trunc(dbms_random.value(10,30)), round(50*dbms_random.value,2)
from dual connect by level < 15;
-- 14 rows inserted
select 'Jim' tbl, count(*) cnt from jim
union all
select 'Results', count(*) from results;
/*
Jim 14
Results 14
*/
insert into jim (id, age, price)
select level, trunc(dbms_random.value(10,30)), round(50*dbms_random.value,2)
from dual connect by level < 15;
/*
Error starting at line : 266 in command -
insert into jim (id, age, price)
select level, trunc(dbms_random.value(10,30)), round(50*dbms_random.value,2)
from dual connect by level < 15
Error report -
ORA-20347: Too many records
ORA-06512: at "BOB.TRG_INS_JIM_AIS", line 6
ORA-04088: error during execution of trigger 'BOB.TRG_INS_JIM_AIS'
But is it really?
*/
select 'Jim' tbl, count(*) cnt from jim
union all
select 'Results', count(*) from results;
/*
Jim 14
Results 28
Well maybe not!!
*/
delete from jim;
delete from results;
commit ;
select 'Jim' tbl, count(*) cnt from jim
union all
select 'Results', count(*) from results;
/*
Jim 0
Results 0
*/
insert into jim (id, age, price)
select level, trunc(dbms_random.value(10,30)), round(50*dbms_random.value,2)
from dual connect by level < 15000;
/*
insert into jim (id, age, price)
select level, trunc(dbms_random.value(10,30)), round(50*dbms_random.value,2)
from dual connect by level < 15000
Error report -
ORA-20347: Too many records
ORA-06512: at "BOB.TRG_INS_JIM_AIS", line 6
ORA-04088: error during execution of trigger 'BOB.TRG_INS_JIM_AIS'
*/
select 'Jim' tbl, count(*) cnt from jim
union all
select 'Results', count(*) from results;
/*
Jim 0
Results 14999
Is this really what you want?
*/
故事的寓意:以一種或另一種方式(而不是數據庫觸發器)在App中執行此規則。 這里的一切都是一個會話。 多個會話會變得更加復雜。
這是一個BEFORE
觸發器,因此新行未包含在SELECT COUNT(*)
因為該行尚未在表中。
嘗試檢查小於16而不是小於或等於16。更改此值:
IF INSERTING AND v_count<=16 THEN
...對此:
IF INSERTING AND v_count<16 THEN
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.