Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
ORACLE PL/SQL:我的SELECT COUNT语句不适用于触发器_Sql_Database_Oracle_Plsql_Triggers - Fatal编程技术网

ORACLE PL/SQL:我的SELECT COUNT语句不适用于触发器

ORACLE PL/SQL:我的SELECT COUNT语句不适用于触发器,sql,database,oracle,plsql,triggers,Sql,Database,Oracle,Plsql,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); begi

因此,我想创建一个触发器,如果表中的记录数超过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,我会收到一条错误消息,这是一个BEFORE触发器,因此新行不包括在select count*中,因为它还不在表中

尝试检查是否小于16,而不是小于或等于16。更改此项:

IF INSERTING AND v_count<=16 THEN
。。。为此:

IF INSERTING AND v_count<16 THEN

这不是触发器适用的问题。让我们观察不同类型的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?
*/ 

这个故事的寓意是:以这样或那样的方式在应用程序中强制执行此规则,而不是数据库触发器。这里的每件事都是一次会议。多个会话会使问题变得更加复杂

即使触发器起作用,您也可以在表中获得16条以上的记录。如果表已经有15条记录,请打开两个数据库会话,让它们插入一条记录,但不要提交。触发器将计数15条记录,因为它不会在另一个会话中看到未限制的插入,并且将允许插入。100%true。我考虑在回答时指出这一点,但上面提到的问题似乎更像是一个练习,而不是一个现实世界的问题,所以我把它省略了,以保持事情的简单。我很高兴你提起这件事。