Oracle约束(Constraint)详解
概述
约束是数据库用来确保数据满足业务规则的手段,不过在真正的企业开发中,除了主键约束这类具有强需求的约束,像外键约束,检查约束更多时候仅仅出现在数据库设计阶段,真实环境却很少应用,更多是放到程序逻辑中去进行处理。这也比较容易理解,约束会一定程度上较低数据库性能,有些规则直接在程序逻辑中处理就可以了,同时,也有可能在面对业务变更或是系统扩展时,数据库约束会使得处理不够方便。不过在我看来,数据库约束是保证数据准确性的最后一道防线,对于设计合理的系统,处于性能考虑数据库约束自然可有可无;不过若是面对关联关系较为复杂的系统,且对系统而言,数据的准确性完整性要高于性能要求,那么这些约束还是有必要的(否则,就会出现各种相对业务规则来说莫名其妙的脏数据,本人可是深有体会的。。)。总之,对于约束的选择无所谓合不合理,需要根据业务系统对于准确性和性能要求的侧重度来决定。
- 主键约束(PRIMARY KEY)
- 唯一性约束(UNIQUE)
- 非空约束(NOT NULL)
- 外键约束(FOREIGN KEY)
- 检查约束(CHECK)
数据库约束
主键约束(PRIMARY KEY)
- 键列必须必须具有唯一性,且不能为空,其实主键约束 相当于 UNIQUE+NOT NULL
- 一个表只允许有一个主键
- 主键所在列必须具有索引(主键的唯一约束通过索引来实现),如果不存在,将会在索引添加的时候自动创建
SQL> alter table emp add constraint emp_id_pk primary key(id);
唯一性约束(UNIQUE)
- 对于UNIQUE约束来讲,索引是必须的。如果不存在,就自动创建一个(UNIQUE的唯一性本质上是通过索引来保证的)
- UNIQUE允许null值,UNIQUE约束的列可存在多个null。这是因为,Unique唯一性通过btree索引来实现,而btree索引中不包含null。当然,这也造成了在where语句中用null值进行过滤会造成全表扫描。
SQL> alter table emp add constraint emp_code_uq unique(code);
非空约束(NOT NULL)
非空约束作用的列也叫强制列。顾名思义,强制键列中必须有值,当然建表时候若使用default关键字指定了默认值,则可不输入。
添加非空约束,语法较特别
SQL> alter table emp modify ename not null;
外键约束(FOREIGN KEY)
外键约束定义在具有父子关系的子表中,外键约束使得子表中的列对应父表的主键列,用以维护数据库的完整性。不过出于性能和后期的业务系统的扩展的考虑,很多时候,外键约束仅出现在数据库的设计中,实际会放在业务程序中进行处理。外键约束注意以下几点:
- 外键约束的子表中的列和对应父表中的列数据类型必须相同,列名可以不同
- 对应的父表列必须存在主键约束(PRIMARY KEY)或唯一约束(UNIQUE)
- 外键约束列允许NULL值,对应的行就成了孤行了
其实很多时候不使用外键,很多人认为会让删除操作比较麻烦,比如要删除父表中的某条数据,但某个子表中又有对该条数据的引用,这时就会导致删除失败。我们有两种方式来优化这种场景:
第一种方式简单粗暴,删除的时候,级联删除掉子表中的所有匹配行,在创建外键时,通过 on delete cascade 子句指定该外键列可级联删除:
SQL> alter table emp add constraint emp_deptno_fk foreign key(deptno) references dept (deptno) on delete cascade;
第二种方式,删除父表中的对应行,会将对应子表中的所有匹配行的外键约束列置为NULL,通过 on delete set null 子句实施:
SQL> alter table emp add constraint emp_deptno_fk foreign key(deptno) references dept(deptno) on delete set null;
实际上,外键约束列和对应的父表列可以在同一张表中,常见的就是表的业务逻辑含义是一棵树,最简单的例子如下(id为主键id,fid为父id,fid存储对id的引用),这种结构的表根据业务要求可通过Oracle的递归查询来获取这种层级关系

检查约束(CHECK)
检查约束可用来实施一些简单的规则,比如列值必须在某个范围内。检查的规则必须是一个结果为true或false 的表达式,比如:
SQL> alter table emp add constraint emp_sex_ck check(sex in('男','女'));
约束状态
很多时候由于业务需要,比如我们有大量的历史数据,需要和现有数据合并,当前表存在数据库约束(如非空约束),而这些历史数据又包含违背非空约束的数据行,为了避免导入时由于违反约束而导入失败,我们通过调整约束状态来达到目的。
数据库约束有两类状态
启用/禁用(enable/disable):是否对新变更的数据启用约束验证
验证/非验证 (validate/novalidate) :是否对表中已客观存在的数据进行约束验证
这两类四种状态从语法角度讲可以随意组合,默认是 enable validate
下面我们来看着四类组合会分别出现什么样的效果:
enable validate : 默认的约束组合状态,无法添加违反约束的数据行,数据表中也不能存在违反约束的数据行;
enable novalidate : 无法添加违反约束的数据行,但对已存在的违反约束的数据行不做验证;
disable validate : 可以添加违反约束的数据行,但对已存在的违反约束的数据行会做约束验证(从描述中可以看出来,这本来就是一种相互矛盾的约束组合,只不过是语法上支持这种组合罢了,造成的结果就是会导致DML失败)
disable novalidate : 可以添加违法约束的数据行,对已存在的违反约束的数据行也不做验证。
拿上面的例子来说,我们需要上传大量违反非空约束的历史数据(从业务角度讲这些数据不会造成系统功能异常),可以临时将约束状态转为 disable novalidate,以保证这些不合要求的数据导入表中
SQL> alter table emp modify constraint emp_ename_nn disable novalidate;
在数据导入完成之后,我们再将约束状态转为enable novalidate 以确保之后添加的数据不会再违反约束
SQL> alter table emp modify constraint emp_ename_nn enable novalidate;
总结
本文介绍了数据库中的五类约束,也提到了数据库约束的四种状态组合,当你由于业务需求或是系统扩展,在一个约束严苛的系统中由于约束限制频繁操作失败的时候,不同组合的约束状态或许能给你另一种处理方案。谢谢支持。
Oracle约束(Constraint)详解的更多相关文章
- MySQL——约束(constraint)详解
该博客说说关于数据库中一个重要的知识点——约束 一.什么是约束约束英文:constraint 约束实际上就是表中数据的限制条件 二.约束作用表在设计的时候加入约束的目的就是为了保证表中的记录完整和有效 ...
- Oracle执行计划详解
Oracle执行计划详解 --- 作者:TTT BLOG 本文地址:http://blog.chinaunix.net/u3/107265/showart_2192657.html --- 简介: ...
- [转]Oracle执行计划详解
Oracle执行计划详解 --- 作者:TTT BLOG 本文地址:http://blog.chinaunix.net/u3/107265/showart_2192657.html --- 简介: ...
- oracle表分区详解
原文来自:http://www.cnblogs.com/leiOOlei/archive/2012/06/08/2541306.html oracle表分区详解 从以下几个方面来整理关于分区表的概念及 ...
- Oracle权限管理详解
Oracle权限管理详解 转载--CzmMiao的博客生活 Oracle 权限 权限允许用户访问属于其它用户的对象或执行程序,ORACLE系统提供三种权限:Object 对象级.System 系统级. ...
- Java从入门到精通——数据库篇Oracle 11g服务详解
装上Oracle之后大家都会感觉到我们的电脑慢了下来,如何提高计算机的速度呢?我们应该打开必要的服务,关闭没有用的服务.下面是Oracle服务的详解: Oracle ORCL VSS Writer S ...
- oracle rac IP详解
rac环境下vip/public/private IP的区别 每个节点要2块网卡, 3个IP,虚拟IP或者叫做业务IP,单个网卡当掉可以“漂”到其他网卡是继续提供服务 在Oracle RAC环境下,每 ...
- oracle tkprof 工具详解
oracle tkprof 工具详解 今天是2013-09-26,进行tkprof工具使用学习,在此记录一下笔记: 一)查看需要跟踪会话信息: select s.sid,s.serial#,s.us ...
- Oracle AWR 报告详解
转自:http://blog.csdn.net/laoshangxyc/article/details/8615187 持续更新中... Oracle awr报告详解 DB Name DB Id In ...
随机推荐
- Java - NIO
java.nio:NIO-2: NIO 面向流的IO体系一次只能处理一个或多个字节/字符,直至读取所有字节/符,且流中的数据不能前后移动.效率低,当数据源中没有数据时会阻塞线程.Java-4提供的新A ...
- 背水一战 Windows 10 (24) - MVVM: 通过 Binding 或 x:Bind 结合 Command 实现,通过非 ButtonBase 触发命令
[源码下载] 背水一战 Windows 10 (24) - MVVM: 通过 Binding 或 x:Bind 结合 Command 实现,通过非 ButtonBase 触发命令 作者:webabcd ...
- MyEclipse10查看Struts2源码及Javadoc文档
1:查看Struts2源码 (1):Referenced Libraries >struts2-core-2.1.6.jar>右击>properties. (2):Java Sour ...
- 在Eclipse中使用Junit进行单元测试练习 实现最大子数组和算法
1.如何在MAC OS X下安装配置java开发工具 http://www.cnblogs.com/coderL/p/5939541.html 2.最大子数组和算法 附上程序运行及测试截图,源码见后 ...
- 新建 ASP.NET Core Web API 项目 -- RESTFul 风格 Hello World!
一.创建一个空项目 请查看 新建 .NET Core 项目 -- Hello World! 一节,新建一个项目: 二.添加引用并修改配置为 Web API (.NET Core 已将 MVC/W ...
- jQuery获取Table-Input控件值封装
- jQuery基础_4
dom对象就是jquery对象的数组组成部分jquery对象和dom对象的转化jquery对象-->dom对象$()[下标]dom对象-->jquery对象$(dom对象) jquery框 ...
- border-radius结合transition的一个小应用(动画)
<head lang="en"> <meta charset="UTF-8"> <title></title> ...
- 1-2 nodejs小节 文件读取
1.表达式 在命令行输入 node回车后,可以在后边输入相应的表达式,进行运算操作 2.阻塞文件读取 var data=fs.readFileSync('input.txt', 'utf-8') ...
- 用原生javascript实现在页面动态显示时间
<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>js ...