如何修改唯一约束以允许一次性异常

时间:2013-11-27 20:13:16

标签: oracle oracle11g sqlplus unique-constraint

 CREATE TABLE SPONSORS (owner_number INT NOT NULL,       
                        requires_anonimity CHAR(3) NOT NULL,                                    
                        CONSTRAINT chk_requires_anonimity CHECK (requires_anonimity IN ('Yes', 'No')),      
                        FOREIGN KEY (owner_number) REFERENCES OWNER (owner_number),
                        PRIMARY KEY (owner_number));



CREATE TABLE DONATIONS (receipt_number NCHAR(6) CHECK(receipt_number BETWEEN 111111 AND 999999),
                        amount_donated NUMBER NOT NULL,
                        document_reference VARCHAR(50) UNIQUE ,
                        donations_event_number INT NOT NULL CHECK,
                        donations_sponsor_number INT NOT NULL,
                        FOREIGN KEY (donations_sponsor_number) REFERENCES SPONSORS(benefactor_number_sponspor) 
            );

我试图摆脱这个命令的是以下实例,     如果捐赠者BOB决定在文件参考中引用的条件x和y上给予100英镑,他应该能够为将来的捐赠设置相同的条件,但是另一个人不能使用他的条件

CREATE UNIQUE INDEX doc_unique_indx
ON DONATIONS ( CASE WHEN donations_sponsor_number = donations_sponsor_number THEN AllOW to use same document_reference ELSE END);

2 个答案:

答案 0 :(得分:1)

看起来你在这里有一个建模问题。如果文档引用必须对特定赞助商是唯一的,则它应该在其自己的表中,并且具有赞助商的外键,并且捐赠表应该具有文档引用表的外键。

答案 1 :(得分:0)

Dave Aldridg是100%的标志。这就是规范化很重要的原因 - 如果你有:

,你的问题就很简单了
SPONSORS (OWNER_NUMBER PK, ...)

DOC_REFS (DOCUMENT_REFERENCE PK,
         DONOR_NUMBER FK REFERENCES SPONSORS(OWNER_NUMBER),
         ...)

DONATIONS (RECEIPT PK,
           DOCUMENT_REFERENCE FK REFERENCES DOC_REFS(DOCUMENT_REFERENCE),
           ...)

如果可能,修复模型,拆分表格。

那说......如果你必须这么做,不要试图用触发器强制执行约束(除非一次只允许一个人使用数据库)。唯一比没有约束更糟的是来自未被强制执行的感知约束的错误安全感。如果你绝对必须用手头的表来解决这个问题,你可以使用“完整性检查”FAST REFRESH MV拉出延迟约束:

CREATE TABLE SPONSORS (owner_number INT NOT NULL,       
                        requires_anonimity CHAR(3) NOT NULL,                                    
                        CONSTRAINT chk_requires_anonimity CHECK (requires_anonimity IN ('Yes', 'No')),      
                        PRIMARY KEY (owner_number));

CREATE TABLE DONATIONS (receipt_number NCHAR(6) CHECK(receipt_number BETWEEN 111111 AND 999999),
                        amount_donated NUMBER NOT NULL,
                        document_reference VARCHAR(50)  ,
                        donations_event_number INT NOT NULL ,
                        donations_sponsor_number INT NOT NULL,
                        FOREIGN KEY (donations_sponsor_number) REFERENCES SPONSORS(owner_number));

CREATE MATERIALIZED VIEW LOG ON DONATIONS WITH ROWID (DOCUMENT_REFERENCE, DONATIONS_SPONSOR_NUMBER) INCLUDING NEW VALUES

CREATE MATERIALIZED VIEW DOC_REF_CONSTRAINT 
REFRESH FAST ON COMMIT
AS 
SELECT DOCUMENT_REFERENCE, MIN(DONATIONS_SPONSOR_NUMBER) MX, MAX(DONATIONS_SPONSOR_NUMBER) MN
FROM DONATIONS
GROUP BY DOCUMENT_REFERENCE

CREATE INDEX DOC_REF_CONSTRAINT_IDX ON DOC_REF_CONSTRAINT(DECODE(MX,MN,0,1/0))


BEGIN
INSERT INTO SPONSORS VALUES (1, 'Yes');
INSERT INTO SPONSORS VALUES (2, 'Yes');
INSERT INTO DONATIONS VALUES ('111111',100,'A',0,1);
INSERT INTO DONATIONS VALUES ('222222',100,'A',0,1);
INSERT INTO DONATIONS VALUES ('333333',100,'C',0,2);
COMMIT;
END;
-- Success!

BEGIN
INSERT INTO SPONSORS VALUES (3, 'Yes');
INSERT INTO SPONSORS VALUES (4, 'Yes');
INSERT INTO DONATIONS VALUES ('444444',100,'A',0,3);
INSERT INTO DONATIONS VALUES ('555555',100,'C',0,3);
INSERT INTO DONATIONS VALUES ('666666',100,'C',0,4);
COMMIT;
END;
--ORA-12008: error in materialized view refresh path
--ORA-01476: divisor is equal to zero
--ORA-06512: at line 7

注意 - 比1/0更有创意 - 你可以设置一个用户定义函数来引发一个易于理解的EXCEPTION。