在不检查现有数据的情况下,在修改表时创建约束

7
我将尝试为Oracle 11g R2附带的OE.PRODUCT_INFORMATION表创建约束条件。该约束条件应使PRODUCT_NAME唯一。
我已尝试以下语句:
ALTER TABLE PRODUCT_INFORMATION
  ADD CONSTRAINT PRINF_NAME_UNIQUE UNIQUE (PRODUCT_NAME);

问题是,在OE.PRODUCT_INFORMATION中已经存在多次出现的产品名称。 执行以上代码会抛出以下错误:
an alter table validating constraint failed because the table has
duplicate key values.

新创建的约束条件有可能不会应用于现有表格数据吗?我已经尝试了 DISABLED 关键字。但是当我启用约束条件时,仍然收到相同的错误消息。


2
你的问题不够清晰。你在问什么?如果一列中有重复的值,那么就不能对它强制执行唯一约束。你必须先删除重复项,然后再添加约束。 - Ollie
谢谢。这实际上就是问题所在;是否有一种方法可以通过修改表来创建约束,而不需要检查现有的数据。 - mhmpl
@Ollie:实际上,在一个包含重复值的列上设置唯一约束是可能的... - Jeffrey Kemp
@JeffreyKemp,不错的线程复活,但你迟了两年!请看jonearles在我的回答中的评论和链接。 - Ollie
我会更新你的回答,因为这个问题在其他地方被引用了。 - Jeffrey Kemp
好的,会做的 Jeffrey。 - Ollie
3个回答

10

您可以使用NOVALIDATE关键字创建一个约束来验证任何新插入或更新的记录,但不会针对旧有数据进行验证,例如:

ALTER TABLE PRODUCT_INFORMATION
  ADD CONSTRAINT PRINF_NAME_UNIQUE UNIQUE (PRODUCT_NAME)
  NOVALIDATE;

如果该列没有索引,此命令将在该列上创建一个非唯一索引。

+1 是的,这在 Oracle 中可以工作。修改表 tes,将 call_type4 的默认值设置为 0,且不允许为空,并且不进行验证。 - Kanagavelu Sugumar

2
如果您想在保留当前重复项的同时强制执行所有未来条目的某种唯一性,那么不能使用UNIQUE约束。您可以在表上使用触发器来检查要插入的值是否已存在于当前表值中,如果已经存在,则防止插入。

http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14251/adfns_triggers.htm

或者您可以删除重复的值,然后强制执行唯一约束条件。
编辑:在Jonearles和Jeffrey Kemp的评论之后,我将补充说明,您实际上可以使用“NOVALIDATE”子句在存在重复值的表上启用唯一约束条件,但是您将无法在受约束的列上拥有唯一索引。
请参见Tom Kyte在这里的解释。
不过,我仍然会担心未来必须支持数据库的人对意图的明显程度。从支持的角度来看,要么删除重复项,要么使用触发器使您的意图清晰明确会更加明显。 YMMV

2
你可以使用唯一约束,但不能使用唯一索引。请参见我的答案:http://stackoverflow.com/questions/7981221/cannot-validate-with-novalidate-option/8005259#8005259 - Jon Heller
Jonearles,谢谢你指出这一点,我没有想到!(+1)我的唯一担忧是对约束的支持。任何新的支持数据库的人都必须知道它,否则他们可能会遇到问题。使用触发器时很明显正在发生什么(尽管不太优雅)。 - Ollie

0
你可以使用可延迟的。
ALTER TABLE PRODUCT_INFORMATION
  ADD CONSTRAINT PRINF_NAME_UNIQUE UNIQUE (PRODUCT_NAME)
deferrable initially deferred NOVALIDATE; 

你(或其他人)能否请解释一下“最初延迟”条款。我正在搜索这个修饰符,但无法完全理解它。 - EAmez
推迟约束只会将验证推迟到提交时进行。如果您希望数据被插入/更新并提交,这并没有什么帮助。 - Jeffrey Kemp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接