Oracle数据库中违反唯一约束的处理

  根据NULL的定义,NULL表示的是未知,因此两个NULL比较的结果既不相等,也不不等,结果仍然是未知。根据这个定义,多个NULL值的存在应该不违反唯一约束。

实际上Oracle也是如此实现的:


SQL> CREATE TABLE T (ID NUMBER);

表已创建。

SQL> ALTER TABLE T ADD UNIQUE (ID);

表已更改。

SQL> INSERT INTO T VALUES (1);

已创建 1 行。

SQL> INSERT INTO T VALUES (1);

INSERT INTO T VALUES (1)

*第 1 行出现错误:

ORA-00001: 违反唯一约束条件 (YANGTK.SYS_C007300)

SQL> INSERT INTO T VALUES (NULL);

已创建 1 行。

SQL> INSERT INTO T VALUES (NULL);

已创建 1 行。

SQL> INSERT INTO T VALUES (NULL);

已创建 1 行。

  但是当唯一约束为复合字段时,则情况发生了变化。根据Oracle文档的描述,对于复合字段的唯一约束,不为空字段的值是不能重复的。也就是说,如果两个字段构成了一个唯一约束,其中一个字段为空,那么另一个字段的值不能出现重复。

SQL> DROP TABLE T PURGE;

表已删除。

SQL> CREATE TABLE T (ID NUMBER, ID2 NUMBER);

表已创建。

SQL> ALTER TABLE T ADD UNIQUE (ID, ID2);

表已更改。

SQL> INSERT INTO T VALUES (1, 1);

已创建 1 行。

SQL> INSERT INTO T VALUES (1, NULL);

已创建 1 行。

SQL> INSERT INTO T VALUES (2, NULL);

已创建 1 行。

SQL> INSERT INTO T VALUES (1, NULL);

INSERT INTO T VALUES (1, NULL)

*第 1 行出现错误:

ORA-00001: 违反唯一约束条件 (YANGTK.SYS_C007301)

SQL> INSERT INTO T VALUES (NULL, NULL);

已创建 1 行。

SQL> INSERT INTO T VALUES (NULL, NULL);

已创建 1 行。

SQL> INSERT INTO T VALUES (NULL, NULL);

已创建 1 行。

  对于全部为NULL的情况,仍然和单字段唯一约束一样,不会造成重复,但是对于部分为NULL的情况,就如上面例子所示,只要其中不为NULL的部分发生了重复,Oracle就认为约束发生了重复。

而这似乎和NULL的定义有所冲突,第一次看concept的时候一直没有搞明白Oracle为什么这么实现,不过这次再看concept的时候,已经想明白了。

由于Oracle的唯一约束是依赖索引实现的,而Oracle的BTREE索引又是不存储NULL值的,所以键值全部为NULL的记录不会记录在索引中,因此也就不会违反唯一约束了,而对于部分为NULL的记录,索引是要记录数值的,因此一旦键值中非NULL部分发生了冲突,Oracle就认为违反了的唯一约束。

Oracle在这里还是选择了自己的方便的方法来实现,而没有完全真正的根据NULL的定义去实现唯一约束。

时间: 2024-10-09 19:05:44

Oracle数据库中违反唯一约束的处理的相关文章

oracle数据库中提供的5种约束

约束作用:用来保持数据的完整性,防止无效数据进入到数据库中.oracle数据库中提供的5种约束,都是限定某个列或者列的组合的.1.主键约束(PRIMARY KEY):在一个表中能唯一的标识一行.主键可以限定在多个列上.2.唯一键约束(UNIQUE key):在一个表中能唯一的标识一行,唯一键也可以限定在多个列上.主键和唯一键的区别:a.一个表中最多只能有一个主键.可以多个唯一键.b.主键所限定的列不能为null,唯一键所限定的列可以为null.3.外键约束(FOREIGN key):   引用表

重复键违反唯一约束

这种情况一般出现在,将.sql文件导入本地的postgresql数据库后,然后创建或更新数据时候会报错: Unique violation: 7 错误: 重复键违反唯一约束"table_name_pkey" 解决办法:1.查看自己报错表的最大id2.在navicate中执行:Select nextval('table_name_id_seq')命令查看这个表的自增序列值目前是多少3.一般只要你能看到这篇文章,说明你的自增序列值一定大于表的最大id4.在navicate中执行:Selec

给Oracle数据库中CLOB字段插入空值

遇到往ORACLE数据库中插入数据时总是报ORA-01084 invalid argument in OCI call错误,经分析是因为表中的一个字段类型为CLOB,并且可为空,当在给该字段插入空值时引发的该错误.后来判断是否为空值,如果为空值使用DBNull.Value,以此解决了该问题. Null 指的是无效的对象引用:而 DBNull 是一个类, DBNull.Value 是它唯一的实例 .DBNull 的实例 DBNull.Value是数据库表中的空数据在 .Net 代码中的表现形式.我

分布式数据库中全局唯一主键

[相关文章] <分布式数据库中全局唯一主键生成策略的设计与实现><activiti5.10解决分布式集群部署的主键问题><分布式环境下数据库主键方案><如何在高并发分布式系统中生成全局唯一Id><分布式环境下ID生成方法总结> <分布式环境下数据库主键方案> [ http://www.2cto.com/database/201309/243195.html ] 在只使用单数据库时,使用自增主键ID无疑是最适合的.但在集群.主从架构上时

如何处理Oracle数据库中的坏块问题

本文主要介绍如何去处理在Oracle数据库中出现坏块的问题,对于坏块产生在不同的对象上,处理的方法会有所不同,本文将大致对这些方法做一些介绍.因为数据库运行时间长了,由于硬件设备的老化,出现坏块的几率会越来越大,因此,做为一个DBA,怎么去解决数据库出现的坏块问题就成了一个重要的议题了. 一:什么是数据库的坏块   首先我们来大概看一下数据库块的格式和结构 数据库的数据块有固定的格式和结构,分三层:cache layer,transaction layer,data layer.在我们对数据块进

EXCEL表数据导入到ORACLE数据库中

将EXCEL表导入ORACLE数据库中 一.建立表 1.建立表 2.查询表 select * from yy; 二.导入程序 在excel中找到需要导入的数据 2.将excel中的数据另存为文本文件(有制表符分割的) 3.在pl*sql中选择tools-->text importer,在出现的窗口中选择"Data from Textfile",然后再选择"Open data file", 在弹出的文件选择框中选中保存有数据的文本文件,此时将会看到data fr

Oracle数据库中的blob类型解析

Oracle的Blob字段比较特殊,他比long字段的性能要好很多,可以用来保存例如图片之类的二进制数据. 写入Blob字段和写入其它类型字段的方式非常不同,因为Blob自身有一个cursor,你必须使用cursor对blob进行操作,因而你在写入Blob之前,必须获得cursor才能进行写入,那么如何获得Blob的cursor呢? 这需要你先插入一个empty的blob,这将创建一个blob的cursor,然后你再把这个empty的blob的cursor用select查询出来,这样通过两步操作

oracle数据库中exp/imp之初次使用

最近使用oracle9i时,遇到了数据库备份和恢复的问题,很多时候与exp和imp的命令使用有关.针对遇到的问题,简单的总结. 问题的背景,就是需要对某张表导入和导出.数据库database1,dateabase2在数据库中涉及的用户主要是 user1,user2,备份的对象主要是表table1. 对于exp和Imp命令的内容网上较多的解说,这里主要解决具体的问题,使用的只是常用的命令项. 1.从database2中导出表 table1 exp userid=system/[email prot

收集Oracle数据库中的SQL基线信息(一)基础信息收集

Oracle数据库中的SQL基线信息,当数据库出现性能问题时,在业务无法提供相应业务信息时,通过对比SQL基线信息来查找SQL的变化. 查找数据库一天内运行次数大于5000次的sqlid select sql_id,sum(EXECUTIONS_DELTA)from dba_hist_sqlstat a,dba_hist_snapshot b where a.snap_id=b.snap_id and a.INSTANCE_NUMBER=b.INSTANCE_NUMBER and to_char