0

我有一个包含错误数据的表,并且想要防止在修复数据时发现插入了新的错误数据,并找出在哪个过程或哪个地方使用这个语句发生。 我首先对不应该重复的列进行UQ约束,但是这使我陷入另一个问题:我只需要在所有列都有值时应用唯一性,如果有空值,我需要在这些列上重复记录。事情是这样的:使用现有的重复值在基于函数的索引上创建唯一约束

CREATE TABLE MYTAB (COL1 NUMBER, COL2 NUMBER, COL3 NUMBER, COL4 NUMBER); --EXAMPLE TABLE. I NEED NO DUPS OVER (COL1, COL3, COL4) 
INSERT INTO MYTAB VALUES (1, 1, 1, 1); --OK 
INSERT INTO MYTAB VALUES (1, 2, 1, 1); -- NOOK 
INSERT INTO MYTAB VALUES (1, 3, NULL, NULL); --OK 
INSERT INTO MYTAB VALUES (1, 4, NULL, NULL); --OK 

如果我创建这样一个约束:

ALTER TABLE MYTAB 
ADD CONSTRAINT U_CONSTRAINT UNIQUE (COL1, COL3, COL4) NOVALIDATE; 

末插入会崩溃。

我试着

CREATE UNIQUE INDEX FN_UIX_MYTAB 
    ON MYTAB (CASE WHEN COL2 IS NOT NULL THEN COL1 ELSE null END, 
       CASE WHEN COL2 IS NOT NULL THEN COL3 ELSE null END 
       CASE WHEN COL2 IS NOT NULL THEN COL4 ELSE null END) ; 

但创建崩溃,因为表中有重复的数据。我将需要创建此索引而不验证现有数据,这意味着索引将仅应用于插入的新记录。

我也试过用:

CREATE INDEX FN_IX_MYTAB 
    ON MYTAB (CASE WHEN COL2 IS NOT NULL THEN COL1 ELSE null END, 
       CASE WHEN COL2 IS NOT NULL THEN COL3 ELSE null END, 
       CASE WHEN COL2 IS NOT NULL THEN COL4 ELSE null END) ; 
ALTER TABLE MYTAB 
ADD CONSTRAINT FN_UIX_MYTAB UNIQUE (COL1, COL3, COL4) USING INDEX FN_IX_MYTAB NOVALIDATE; 

但是这给了我错误:

ORA-14196: Specified index cannot be used to enforce the constraint. 

有没有办法做我已经解释了,或者我应该防止错误插入另一种方式,当我寻找问题的根源?任何建议也将受到赞赏。

+1

如果这是一个临时解决方法,直到您清理您的表,也许使用触发器来防止新的重复,然后删除并添加适当的约束。 – OldProgrammer

+0

你的问题陈述不太合理。您想要在col1,col3,col4上创建唯一索引,但是您希望允许(1,...,NULL,NULL)被复制。这不是UNIQUE在这三列中的含义 - 问题不是“破坏独特性的旧数据”。即使你首先创建表格,然后添加这个唯一的约束,然后你第一次填充表格,你将无法添加示例中的所有行,完全出于这个原因。这与预先存在的数据有什么关系? – mathguy

+0

@mathguy我想只有当这3列有价值时才应用UNIQUE。正如OldProgrammer指出的那样,这是一个临时解决方法,我只需要找到问题的根源并找到一个干净的解决方案。 – EAmez

回答

0

以下是一种可能的方法。创建物化视图,刷新提交(如果情况允许,最好快速刷新;在这种情况下,他们应该)。该MV会是这样的

create materialized view mymv 
refresh fast on commit 
as 
select col1, col3, col4 
from mytab 
where col1 is not null and col3 is not null and col4 is not null 
; 

然后把上的MV(COL1,COL3,COL4)的唯一约束。

+0

但是,视图中的约束不会阻止插入“错误”的数据。 此外,我试过你的解决方案,但不起作用,因为MyTab没有PK,因为使每个记录唯一的列是有时需要为空的列。是的,我知道这是一个奇怪的场景......但是这是很久以前其他人做出来的方式:( – EAmez

+1

缺少PK确实是一个问题,但是否则,MV **中的约束将会** “错误的”数据被插入,对于这种场景,这是一种非常常见的策略,我并没有发明它!它的工作原理是这样的:你试图插入“错误”的数据,在提交时,必须刷新MV。 MV拒绝新的行,从而使整个交易无效。 – mathguy