0%
在线 SQL
- http://sqlfiddle.com/
- MySQL 5.6
SQL 完整性
关系模型中的完整性
实体完整性
- 关系的主码中的属性值不能为空值
- 实体是相互可区分的
参照完整性
- 外码必须和某个参照的属性相同
- 必须与客观存在的实体发生联系
用户定义的完整性
- 用户针对具体应用环境定义的完整性约束条件
- 例如一些具体的限定
- sno要求是8位整数,首位是0或1
- 飞行员的飞行里程与星级评定
- 选课人数不能少于10人,多于100人
- 在本地纳税记录超过5年才有购房资格
- 婚姻登记必须购买百年好合保险
比较
- 实体完整性和参照完整性由系统自动支持
- 系统提供定义和检验用户定义的完整性的机制
约束类型
- 列级约束
- 行级约束
- 表级约束
- 查看约束:sp_helpconstraint
- SQL
- primarykey
- unique
- foreignkey
- check
- default
约束系统表
constid |
int |
约束号 |
id |
int |
拥有该约束的表ID |
colid |
smallint |
在其上定义约束的列ID,如果是表约束则为0 |
status |
int |
位图指示状态。可能的值包括: 1 =
PRIMARY KEY 约束 2 = UNIQUE KEY 约束 3 = FOREIGN KEY 约束 4
= CHECK 约束 5 = DEFAULT 约束 16 = 列级约束 32 =
表级约束 |
primary key 与 unique
- 都是通过唯一性索引来支持
- 区别
- primary key 不能为空值,unique 可以为空值
- unique 列只能有一个 null
- unique 可以定义在多个列上,此时可以出现多个 null
1 2 3 4 5 6
| create table t1 ( col1 intunique, col2 int, col3 int, unique(col2,col3) )
|
1 |
3 |
4 |
2 |
5 |
null |
null |
6 |
null |
1 2 3 4 5 6 7 8 9 10 11 12
| create table t1 ( col1 int unique, col2 int, col3 int, unique(col2,col3) ); insert t1 values(1,1,1); insert t1 values(2,1,null); insert t1 values(3,1,null); insert t1 values(4,1,null);
|
primary key 与 unique 的背后
foreign key
- 基本关系:主码所在的关系
- 依赖关系:外码所在的关系
- 参照完整性
- 当外码所在的表需要插入一个记录的时候,需要检查外码的值再主码中存在
- 当主码所在的表删除一个记录的时候,可能也会影响参照完整性
foreign key 的三种定义方式
RESTRICT 方式
- 只有当依赖关系中没有一个外码值与要删除(更新)的基本关系的主码值相对应时,才可以删除(更新)该行(的主码),否则系统拒绝此删除操作
CASCADE方式
- 将依赖关系中所有外码值与基本关系中要删除的主码值所对应的行一起删除(将依赖关系中所有与基本关系中要修改的主码值所对应的外码值一起修改为新值)
SET NULL方式
- 删除(更新)基本关系中的行时,将依赖关系中与基本关系中被删(更新)主码值相对应的外码值置为空值
表级约束
1 2 3 4 5 6 7 8
| create table SC ( sno char(8), cno char(10), grade smallint, primay key(sno,cno), check(sno in(select sno from S)), check(cno in(select cno from C)) )
|
- 好像是在声明外码约束,有一些细节上的区别
- check 定义在 SC 中,当修改 S 表或 C
表的时候是不会有检查的
约束命名及其定义
1 2
| alter table ... drop constraint ... alter table ... add constraint ...
|
1 2 3 4 5 6
| create table S ( sno char(8) constraint S_PK primary key ) alter table S drop constraint S_PK alter table SC add constraint SC_CHECK check(sno in(select sno from S))
|
约束检查
- 先 drop constraint,在插入之后再 add constraint
- 不可行的,可能会有不满足约束条件的数据混入,不安全
- 可以先整理成一个树形的结构,然后从根部开始插入数据
延迟约束
- deferred constraints
- 将多个更新操作语句放入一个事务,在提交时才检查约束
- 如何设置延迟约束
1 2 3 4 5
| [not] deferrable initially deferred [immediate]
set constraint 约束名 deferried
|
1 2 3 4 5 6 7 8 9 10
| create table emp( eno char(10) primary key, ename char(20), mgr char(10) constraint FK_Constraint foreign key references emp(eno) deferrable initially immediate )
set constraint FK_Constraint deferried
|
SQL Server 的约束开关
1 2 3 4 5
| create table t1(col_a INT) insert into t1 values(-1) alter table t1 with nocheck add constraint skip_check check(col_a > 1) insert into t1 values(-2)
|
1 2 3
| alter table t1 nocheck constraint skip_check insert into t1 VALUES(-2) alter table t1 check constraint skip_check
|
- 上面的操作很危险,可能混入不满足约束条件的记录
- SQL Server 提供了一个补救措施
函数约束
例子 1
- 当插入一个新行的时候,使用的值是当前没有使用的最小值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| create table noGap( no int primary key, name varchar(10) )
create function fn_noGap_minUnusedKey() returns int as begin if(not exists(select * from noGap where no = 1)) return 1 declare @min_unused_no int select @min_unused_no = min(no + 1) from noGap NO1 where not exists( select * from noGap NO2 where NO2.no = NO1.no + 1 ) return @min_unused_no end
alter table noGap add constraint DF_no default(fn_noGap_minUnusedKey())for no
|
例子 2
1 2 3 4 5 6 7 8 9
| create function fn_registerCount(@cno varchar ) returns int as begin return ( selectcount(*) from sc where cno= @cno ) End
|
1 2
| alter table sc add constraint CK_registerCount check(fn_registerCount(cno) <= 100)
|
assertion
1 2 3 4 5 6 7 8 9
| create assertion AtoB check ( not exists ( select A from R group by A having count(distinct B) > 1 ) )
|