簡體   English   中英

ORACLE PL / SQL:我的SELECT COUNT語句不適用於觸發器

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM