2014-09-20 124 views
0

我想創建一個觸發器,就像一個異常,不會讓無序對在數據集中被插入或更新兩次。唯一對約束的觸發器

例如,給定集合{A,B},其中A和B都是主鍵且列中存在{A,B}的列,我不想讓集合{B,A}去因爲這種關係已經用{A,B}定義了。

這裏是我的嘗試,但它給Trigger created with compilation errors.,我也看不到如何做到這一點對newold信息。

CREATE TRIGGER pair 
BEFORE INSERT OR UPDATE ON pairing 
DECLARE exists_pair NUMBER; 

BEGIN 
    SELECT MAX(COUNT_VAL) INTO exist_pair 
    FROM (SELECT COUNT(*) FROM pairing p, pairing p2 WHERE p2.element_one = p.element_two AND p.element_one = p2.element_two) 

    IF exist_pair > 0 THEN 
     RAISE SOME_EXCEPTION; 
    END IF; 
END; 

顯然這不是我想要的,但它提供了一個想法。這將每次返回0,直到出現錯誤條目,然後它會說每個條目有效或無效......所以這不是我想要的,但我不知道如何在此上下文中使用:new:old

這對oracle有效。

下面是一個例子的SQLfiddle插入失敗了: http://sqlfiddle.com/#!4/1afb7/1/0

+0

使'(element_one,element_two)'有一個唯一的約束(我認爲你已經擁有了這個)並添加一個檢查約束'element_one Laurence 2014-09-20 22:41:32

+0

如果第一次插入時e1 = B且e2 = A會怎麼樣? – DCookie 2014-09-20 23:09:06

+0

表中已經存在element_one> element_two,它不是一個想要的約束。 – robert7080 2014-09-20 23:46:57

回答

5

函數的索引將工作:

create unique index unique_pair_ix on pairing (least(element_one,element_two),greatest(element_one,element_two)); 

BTW:使用行觸發器選擇從同一個表會導致:

ORA-04091: table XXXX is mutating, trigger/function may not see it 

如果您嘗試在單個語句中插入或更新多個單一行。所以你不能使用:OLD和:NEW。

2

例如,給定集合{A,B},其中A和B都是主鍵,列中存在{A,B},我不想讓集合{B,A }存在,因爲該關係已經用{A,B}定義。

執行唯一性的最直接的方法是添加唯一索引。但是,一個「簡單」的指標將無法正常工作:

-- This does not help here 
CREATE UNIQUE INDEX sample_uniq_ab_fn ON SAMPLE (B,A); 

假設PRIMARY KEY(A,B),在此設置,插入(A=1,B=2)時,你會簡單地強制執行的(1,2)唯一性主鍵索引(2,1)在我的獨特的唯一性指數。這不會阻止在主鍵索引中插入(A=2,B=1),因爲(2,1)而不是。在唯一索引中也不是(1,2)


在這裏,你需要一個function based index,只要你想(分(A,B),MAX(A,B))是唯一的。類似的東西:

CREATE TABLE SAMPLE (
    A NUMBER(3), 
    B NUMBER(3), 
    PRIMARY KEY (A,B)); 


CREATE UNIQUE INDEX sample_uniq_ab_fn 
    ON SAMPLE (CASE WHEN A < B THEN A ELSE B END, 
       CASE WHEN A < B THEN B ELSE A END); 

INSERT INTO SAMPLE(A,B) VALUES (10,20) -- OK 
INSERT INTO SAMPLE(A,B) VALUES (20,10) -- ORA-00001: unique constraint (SYLVAIN.SAMPLE_UNIQ_AB_FN) violated 
+1

我承認你的答案有些冗長 - 但它與我的答案有什麼不同? – 2014-09-21 10:26:18

+0

@JensKrogsboell老實說,我甚至沒有在3/4小時前發表我的回答。也不是DCookie的。這就是我剛剛編輯的原因,以解釋爲什麼後來不正確。我認爲這不是問題,他們很可能會根據時間戳接受OP。 – 2014-09-21 10:28:25

+0

夠公平 - 而且你對問題的解釋是相當不錯的:) – 2014-09-21 10:30:35

0

對於徹底,我將發佈我的回答,我終於結束了通過觸發器進行的緣故,但它確實從錯誤

ORA-04091: table XXXX is mutating, trigger/function may not see it

CREATE OR REPLACE TRIGGER pair 
BEFORE INSERT ON pairing 
FOR EACH ROW 
DECLARE 
    found_count number; 
BEGIN 
    SELECT COUNT(1) INTO found_count FROM pairing 
    WHERE (element_1=:new.element_2 AND element_2=:new.element_1); 
    IF found_count = 1 THEN 
     RAISE_APPLICATION_ERROR(-20001, 'The pairing already exists'); 
    END IF; 
END; 
. 
RUN; 

它受苦對我來說很重要,因爲你必須在sqlplus中運行show errors,以便在出現Trigger created with compilation errors.時提供Trigger created with compilation errors.