2014-09-20 84 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.