【问题标题】:Create Unique Constraint over function based index with existing duplicate values使用现有重复值在基于函数的索引上创建唯一约束
【发布时间】:2017-06-12 16:57:40
【问题描述】:

我有一个包含错误数据的表,我想防止在我修复数据时插入新的错误数据并找出导致这种情况发生的过程或句子的位置。 我首先对不应该重复的列进行了 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.

有没有办法按照我的解释进行操作,或者我应该在寻找问题根源时以其他方式防止错误插入?任何建议也将不胜感激。

【问题讨论】:

  • 如果在清理表之前这是一个临时解决方法,也许可以使用触发器来防止新的重复,然后删除并添加适当的约束。
  • 您的问题陈述不太合理。您想在 col1、col3、col4 上创建唯一索引,但您希望允许 (1, ..., NULL, NULL) 被复制。这不是 UNIQUE 的意思,在这三列上 - 问题不是“违反唯一性的旧数据”。即使您首先创建表,然后添加此唯一约束,然后第一次填充表,您将无法添加示例中的所有行,正是由于这个原因。这与预先存在的数据有什么关系?
  • @mathguy 我希望只有当这 3 列具有价值时才应用 UNIQUE。这是一个临时解决方法,正如 OldProgrammer 所指出的那样,我只在找到问题的根源并找到干净的解决方案时才需要它。

标签: oracle duplicates unique-constraint check-constraints deferred-execution


【解决方案1】:

这是一种可能的方法。创建一个物化视图,在提交时刷新(如果情况允许,最好快速刷新;在这种情况下,他们应该这样做)。 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) 上加上一个唯一的约束。

【讨论】:

  • 但是视图中的约束不会阻止“错误”数据的插入。另外,我已经尝试过您的解决方案但不起作用,因为 MyTab 没有 PK,因为使每条记录唯一的列是有时需要为空的列。是的,我知道这是一个奇怪的场景……但这是很久以前别人做事的方式:(
  • 没有PK确实是个问题。但除此之外,MV 中的约束防止插入“错误”数据。对于这种情况,这是一个非常常见的策略,我不只是发明它!它的工作原理是这样的:您尝试插入“错误”的数据。提交时,必须刷新 MV。 MV 拒绝新行,从而使整个事务无效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-06
相关资源
最近更新 更多