2014-09-20 88 views
1

我创建2名表的员工和客户。而员工表的代码是在这里:在更新触发在oracle?

create table employees(
employeeNumber  number not null, 
lastName   varchar2(30) not null, 
firstName   varchar2(30) not null, 
email    varchar2(50) not null, 
officeCode   varchar2(10) not null, 
assignTo   number default null, 
jobTitle   varchar2(100) not null, 
primary key (employeeNumber), 
foreign key (officeCode) references offices(officeCode), 
foreign key (assignTo) references employees(employeeNumber) 
); 

这里assignTo是他自己的表,员工的外键和employeeNumber是汽车increment.Some插入样品是在这里:

insert into employees (lastName,firstName,email,officeCode,jobTitle) 
values ('hasan','rumy','[email protected]','123','manager'); 
insert into employees (lastName,firstName,email,officeCode,assignTo,jobTitle) 
values ('hasan','rakib','[email protected]','123', 1 ,'assistant manager'); 

客户表的代码是在这里:

create table customers (
customerNumber number not null, 
customerName  varchar2(50) not null, 
phone    varchar2(20) not null, 
address   varchar2(70) not null, 
city    varchar2(50) not null, 
postalCode  varchar2(15) not null, 
country   varchar2(40) not null, 
salesRepEmployeeNumber number default null, 
primary key(customerNumber), 
foreign key (salesRepEmployeeNumber) references employees (employeeNumber) 
); 

customerNumber之是汽车increment.some样本投放是在这里:

insert into customers 
(customerName,phone,address,city,postalCode,country,salesRepEmployeeNumber) 
values ('roxy','017456','holy park','kolia','Z143','something',1); 

现在我创建员工表的更新employeeNumber列之前,其执行对级联更新触发器和代码是在这里:

create or replace trigger employees_update 
before update of employeeNumber on employees 
for each row 
begin 
update employees 
set 
assignTo = :new.employeeNumber 
where assignTo = :old.employeeNumber; 
update customers set 
salesRepEmployeeNumber = :new.employeeNumber 
where salesRepEmployeeNumber = :old.employeeNumber; 
end; 
/

高于一切是正确的预言,但问题是什么时候更新员工table.The更新代码是在这里:

update employees set employeeNumber = 134 where employeeNumber = 1; 

的问题是在这里:

ORA-04091: table RUMY.EMPLOYEES is mutating, trigger/function may not see it 
ORA-06512: at "RUMY.EMPLOYEES_UPDATE", line 2 
ORA-04088: error during execution of trigger 'RUMY.EMPLOYEES_UPDATE' 

1. update employees set employeeNumber = 134 where employeeNumber = 1; 

据我所知,这是一个系统问题,所以我犯了错误?我不能让员工表的外键assignTo?还注意到同样的事情在mysql中正常工作。先行谢谢你回答这个长问题。

+1

运行此'SHOW ERRORS TRIGGER employees_update'获取更多详细信息 – Mihai 2014-09-20 17:06:09

+0

查询'show errors trigger employees_update'发生错误,即:“无效的SQL语句”。 – Rumy 2014-09-20 18:05:12

回答

2

当你发现,你不能从同一个表中选择一个行级触发器被定义为反对;它会导致表异常异常。

然后 - 假设至少甲骨文11,这将需要在早期版本

CREATE OR REPLACE TRIGGER employees_update 
    FOR UPDATE ON employees 
    COMPOUND TRIGGER 

    TYPE employeeNumberRec IS RECORD 
    (oldEmployeeNumber employees.employeeNumber%TYPE 
    ,newEmployeeNumber employees.employeeNumber%TYPE); 
    TYPE employeeNumbersTbl IS TABLE OF employeeNumberRec; 
    g_employeeNumbers employeeNumbersTbl; 

BEFORE STATEMENT 
IS 
BEGIN 
    -- Reset the internal employees table 
    g_employeeNumbers := employeeNumbersTbl(); 
END BEFORE STATEMENT; 

AFTER EACH ROW 
IS 
BEGIN 
    -- Store the updated employees 
    IF :new.employeeNumber <> :old.employeeNumber THEN   
    g_employeeNumbers.EXTEND; 
    g_employeeNumbers(g_employeeNumbers.LAST).oldEmployeeNumber := :old.employeeNumber; 
    g_employeeNumbers(g_employeeNumbers.LAST).newEmployeeNumber := :new.employeeNumber; 
    END IF; 
END AFTER EACH ROW; 

AFTER STATEMENT 
IS 
BEGIN 
    -- Now update the child tables 
    FORALL l_index IN 1..g_employeeNumbers.COUNT 
    UPDATE employees 
    SET assignTo = g_employeeNumbers(l_index).newEmployeeNumber 
    WHERE assignTo = g_employeeNumbers(l_index).oldEmployeeNumber; 
    FORALL l_index IN 1..g_employeeNumbers.COUNT 
    UPDATE customers 
    SET salesRepEmployeeNumber = g_employeeNumbers(l_index).newEmployeeNumber 
    WHERE salesRepEmployeeNumber = g_employeeNumbers(l_index).oldEmployeeNumber; 
END AFTER STATEMENT; 

END; 

编辑拆分成单独的触发器

此外,您将需要进行外键约束参考此表推迟例如

CREATE TABLE employees 
    (employeeNumber NUMBER  NOT NULL 
    ,lastName  VARCHAR2(30) NOT NULL 
    ,firstName  VARCHAR2(30) NOT NULL 
    ,email   VARCHAR2(50) NOT NULL 
    ,officeCode  VARCHAR2(10) NOT NULL 
    ,assignTo  NUMBER DEFAULT NULL 
    ,jobTitle  VARCHAR2(100) NOT NULL 
    ,PRIMARY KEY (employeeNumber) 
    ,FOREIGN KEY (officeCode) 
    REFERENCES offices (officeCode) 
    ,FOREIGN KEY (assignTo) 
    REFERENCES employees (employeeNumber) 
    DEFERRABLE 
    INITIALLY DEFERRED 
) 

CREATE TABLE customers 
    (customerNumber   NUMBER  NOT NULL 
    ,customerName   VARCHAR2(50) NOT NULL 
    ,phone     VARCHAR2(20) NOT NULL 
    ,address    VARCHAR2(70) NOT NULL 
    ,city     VARCHAR2(50) NOT NULL 
    ,postalCode    VARCHAR2(15) NOT NULL 
    ,country    VARCHAR2(40) NOT NULL 
    ,salesRepEmployeeNumber NUMBER DEFAULT NULL 
    ,PRIMARY KEY (customerNumber) 
    ,FOREIGN KEY (salesRepEmployeeNumber) 
    REFERENCES employees (employeeNumber) 
    DEFERRABLE 
    INITIALLY DEFERRED 
) 

注:如果违反约束,这将个别DML语句后不会导致错误的COMMIT

+0

仍然显示这个问题@DrabJay“完整性约束(RUMY.SYS_C0027919825)违反 - 发现儿童记录”,也感谢帮助我了解一些新功能。 – Rumy 2014-09-22 11:39:00

+0

@RumyHasan您将需要使用外键约束来引用employees.employeeNumber'DEFERRABLE';和'DEFFERED'来完成这个事务,或者通过table语句或者通过'ALTER SESSION'语句。 – DrabJay 2014-09-22 11:59:39

+0

我不明白,所以你可以给我一些例子或任何可以帮助我的链接吗?请注意,当我想更新时,上述评论问题就会发生。 – Rumy 2014-09-22 13:52:40

-1

您可以在以下方式重新编写上述触发,以避免问题:

create or replace trigger employees_update 
before update of employeeNumber on employees 
for each row 
begin 
emp_upd_trg_proc(:new.employeeNumber,:old.employeeNumber); 
update customers set 
salesRepEmployeeNumber = :new.employeeNumber 
where salesRepEmployeeNumber = :old.employeeNumber; 
end; 
/

create or replace procedure emp_upd_trg_proc 
(new number, old number) 
is 
pragma autonomous_transaction; 
begin 
update employees 
set 
assignTo = new 
where assignTo = old; 
commit; 
end; 

/

+0

使用自治事务处理突变触发器错误永远不合适。首先,它会破坏事务完整性 - 原始更新可能会回滚,但自治事务不可能,因此您可能会处于无效状态。自治事务无法看到由触发事务作出但未提交的数据更改,因此,如果您的过程试图将'assignTo'指向作为父事务的一部分插入的行,则可能会生成外键异常。 – 2014-09-20 18:33:41