2014-09-20 93 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