2014-03-07 15 views
2

我想創建一個觸發器,以檢查是否有員工在我的emp_mb表中已經存在,我得到這個錯誤信息觸發要檢查新員工不存在

ORA-00969:缺少關鍵字

有任何想法嗎 ?

CREATE OR REPLACE TRIGGER adduser_mb 
BEFORE 
INSERT OR UPDATE emp_id 
ON emp_mb 
FOR EACH ROW 
DECLARE 
DUMMY INTEGER; 
BEGIN 
    SELECT COUNT(*) INTO DUMMY 
    FROM emp_mb 
    WHERE emp_id = :new.emp_id 

    IF (dummy > 0) 
     THEN raise_application_error(-20501 
     'Employee ID' || :new.emp_id || ' already exists'); 
END IF; 
END; 
+3

爲什麼不使用唯一約束或主鍵? –

回答

3

我認爲你缺少一個OF

BEFORE 
INSERT OR UPDATE OF emp_id 
ON emp_mb 

順便說一句,你可以只使用一個唯一的約束,不是嗎?

8

你不能在單一(非複合)觸發器中實際做到這一點。

emp_mb上的行級觸發器通常不能查詢emp_mb。一旦你解決了語法問題,你會得到一個變異的表格異常。

確保emp_id唯一的正確方法是在表上創建唯一約束。

alter table emp_mb 
    add(constraint uk_emp_id unique (emp_id)); 

如果你真的,真的,真的想和觸發器來做到這一點,你需要多個觸發器(或者,如果你使用11.2實現多個觸發器複合觸發器)。你需要一個包含emp_id值的包。您需要一個用於初始化該集合的before語句觸發器。您需要一個行級觸發器,將:new.emp_id值插入到該包的集合中。然後你需要一個after語句觸發器來遍歷集合並執行檢查。這是很多你必須實現,調試和維護的移動部分。

但它實際上不僅僅是代碼的擴散 - 你還需要實現自己的序列化機制。否則,假設您允許系統中有多個用戶,那麼兩個會話都可以插入同一行,並且每個會話的檢查都會成功,然後讓兩個會話都提交,並在表中爲您提供重複值。這意味着您還需要實現一些邏輯,以確保只有一個會話可以在任何時間點將數據插入此表中。反過來,這將大大降低系統的可擴展性,並且很可能會導致維護問題,在這些維護問題中會話鎖定,阻止系統中的其他人,直到DBA找到並殺死他們。

+4

直到DBA發現並殺死會話或開發人員? –

+2

@AlexPoole - 取決於DBA以及他或她的心情。這兩種選擇都適用。 –