【问题标题】:Unique constraint violated when I have a non-unique index当我有一个非唯一索引时违反了唯一约束
【发布时间】:2016-05-10 09:42:35
【问题描述】:

在我的数据仓库中,我的表在 (ID,IDATE,NAME,GENERATION,O_ID,NODE_ID) 列上具有唯一键 TABLE_UK,在 (ID,NAME,GENERATION,STRUCTURE_AREA,O_ID) 列上具有非唯一索引 PER_INDEX

从源表加载数据时收到错误消息:

ORA-00001:违反唯一约束 (PER_INDEX)

我检查了唯一的列,但没有重复。

为什么我在非唯一索引上收到此唯一约束违规错误?

此外,为了将数据加载到目标表中,我是否需要删除此索引或有其他方法可以做到吗?

【问题讨论】:

  • 能否请您发布您的表格的完整 DDL,或者至少是 PER_INDEX 的描述?
  • 您可以有一个由非唯一索引支持的唯一约束。 user_indexesuser_constraints 在您的餐桌上显示什么?

标签: sql oracle unique-constraint unique-index


【解决方案1】:

如果您先创建索引,则可以有一个由非唯一索引支持的唯一约束:

create table t42 (id number);

Table T42 created.

create index per_index on t42(id);

Index PER_INDEX created.

alter table t42 add constraint per_unique unique (id);

Table T42 altered.

select index_name, uniqueness
from user_indexes where table_name = 'T42';

INDEX_NAME                     UNIQUENES
------------------------------ ---------
PER_INDEX                      NONUNIQUE

select constraint_name, constraint_type, status, deferrable, index_name
from user_constraints where table_name = 'T42';

CONSTRAINT_NAME                C STATUS   DEFERRABLE     INDEX_NAME                   
------------------------------ - -------- -------------- ------------------------------
PER_UNIQUE                     U ENABLED  NOT DEFERRABLE PER_INDEX                     

从名称看来,它很可能是先作为索引添加的,然后再将约束置于顶部。

分两步执行此操作的一个原因是,如果您知道现有数据不是唯一的,但您希望所有新数据都是唯一的;然后您可以创建一个非唯一索引,并使用 novalidate 子句添加约束:

alter table t42 add constraint per_unique unique (id) novalidate;

添加新行时,仍然可以使用非唯一索引快速检查是否已经存在匹配条目,如果存在,约束可以抛出异常。对于该检查,索引是否唯一并不重要。唯一真正的区别是检查可能得到不止一个现有匹配,但约束只关心它是非零的。

如果您使唯一约束可延迟,Oracle 也会自动创建非唯一索引;使用唯一索引会立即引发异常,因为无法推迟检查:

create table t42 (id number);

Table T42 created.

alter table t42 add constraint per_unique unique (id) deferrable;

Table T42 altered.

select index_name, uniqueness
from user_indexes where table_name = 'T42';

INDEX_NAME                     UNIQUENES
------------------------------ ---------
PER_UNIQUE                     NONUNIQUE

select constraint_name, constraint_type, status, deferrable, index_name
from user_constraints where table_name = 'T42';

CONSTRAINT_NAME                C STATUS   DEFERRABLE     INDEX_NAME                   
------------------------------ - -------- -------------- ------------------------------
PER_UNIQUE                     U ENABLED  DEFERRABLE     PER_UNIQUE                    

请注意,如果您分两步创建约束,则约束不必与索引具有相同的名称 - 当您添加约束时,它将使用与约束所针对的列匹配的任何索引。自动创建索引时,约束和索引具有相同的名称。


除非您将其删除,否则您无法加载违反该约束的数据,但由于它的存在可能是有原因的,因此不能轻易采取行动。您需要了解约束存在的原因,以及您的数据违反约束的原因——其中一个可能是错误的,但我们无法真正帮助您确定哪个。这是一项业务决策,也是一项技术决策。

【讨论】:

  • 所以你的意思是非唯一索引可以作为表的唯一约束?索引“PER_INDEX”具有非唯一性的唯一性,并且是正常类型。
  • @priya77 - 约束使用非唯一索引,是的;我不太确定它在幕后做了什么,但我想它可以快速使用索引来查看是否已经存在违反约束的值。为此,索引本身是否唯一并不重要。
  • 我的索引是出于性能目的而创建的。我在源表中检查如下: Select count(),ID,NAME,GENERATION,STRUCTURE_AREA,O_ID from target_table group by ID,NAME ,GENERATION,STRUCTURE_AREA,O_ID 有 count()>1;此查询返回
  • @priya77 - 索引通常是。这并没有告诉您为什么将唯一约束添加到索引之上。检查你的约束。查看user_objects 并比较索引和约束的created 时间也可能很有趣。并且您上一条评论中的查询仅查看源表,而不是目标 - 当您将源行添加到目标时,错误就会出现。您可能没有单独的重复项。
  • 问题是我无法将它们两个一起比较,因为两个表中的数据都非常庞大。很多时候,每当我尝试运行查询来比较它们时,SQL 开发人员都会被绞死。因此想找到其他方法来修复 iisue
猜你喜欢
  • 2020-04-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-03
相关资源
最近更新 更多