SQL 外键约束


如果表A的主关键字是表B中的字段,则该字段称为表B的外键,表A称为主表,表B称为从表。外键是用来实现参照完整性的,不同的外键约束方式将可以使两张表紧密的结合起来,特别是修改或者删除的级联操作将使得日常的维护工作更加轻松。

在sqlite中,针对 delete和update有以下约束:

set null: 父值被删除或者不存在了,则剩余的子值将改为 null

set default:父值被删除或者不存在了,子值将被改为默认值

cascade: 父值更新时,子值也将被更新,父值被删除时,所有子值 也将被删除;注意cascade的删除功能,可能带来意想不到的结果

restrict:跟新或者删除父值时,都将被阻止

no action:跟新或者删除父值时,不干涉操作,在整个语句的结尾报错


PS:

deferrable语句(deferrable语句控制约束语句是立即强制执行还是延迟到整个事务结束时执行)

1.deferrable initially immediate(初始化立即执行)

2.deferrable initially deferred(初始化延迟执行)


来看下面的代码:

  SQL> create table t

    ( x int constraint  check_x check ( x > 0 )

  deferrable

  initially immediate,

    y int constraint  check_y check ( y > 0 )

  deferrable

  initially deferred

    )

    /

  Table created.

  SQL> insert into t values ( 1,1 );

  1 row created.

  SQL> commit;

  Commit complete.

  所以,当两个约束同时满足时才能正确无误地插入行。但是,如果我试图插入违反CHECK_X约束(初始化立即执行的约束)的行,则系统会立即检验约束,并得到下面的结果:

  SQL> insert into t values ( -1,1);

  insert into t values ( -1,1)

  *

  ERROR at line 1:

  ORA-02290: check constraint

  (OPS$TKYTE.CHECK_X) violated

  由于CHECK_X是可延迟但初始化为立即执行的约束,所以这一行立刻被拒绝了。而CHECK_Y则不同,它不仅是可延迟的,而且初始化为延迟执行,这就意味着直到我用COMMIT命令提交事务或将约束状态设置为立即执行时才检验约束。

  SQL> insert into t values ( 1,-1);

  1 row created.

  现在它是成功的(总之到目前为止是成功的)。我将约束检验延迟到了执行COMMIT的时候:

  SQL> commit;

  commit

  *

  ERROR at line 1:

  ORA-02091: transaction rolled back

  ORA-02290: check constraint

  (OPS$TKYTE.CHECK_Y) violated

  此时数据库将事务回滚,因为违反约束导致了COMMIT语句的失败。这些语句说明了初始化立即执行与初始化延迟执行约束之间的区别。initially(初始化)部分指定Oracle什么时候会进行默认的约束检验--是在语句结束时[immediate(立即执行)],还是在事务结束时[deferred(延迟执行)]。我还要说明deferred(可延迟)子句有什么用。我可以发出命令,让所有可延迟的约束变为延迟执行的。注意,你也可以对一个约束使用该命令;你不必让所有可延迟的约束都变为延迟执行的:

  SQL> set constraints all deferred;

  Constraint set.

  SQL> insert into t values ( -1,1);

  1 row created.

  由于将初始化立即执行的约束设置为延迟执行的模式,这个语句似乎执行成功;但是,当我用COMMIT语句提交事务时,看一下会发生什么:

  SQL> commit;

  commit

  *

  ERROR at line 1:

  ORA-02091: transaction rolled back

  ORA-02290: check constraint

  (OPS$TKYTE.CHECK_X) violated

  事务提交失败并回滚,因为在COMMIT语句之后对约束进行了检验。相反,我可以将初始化为延迟执行的约束变为"立即"执行的约束:

  SQL> set constraints all immediate;

  Constraint set.

  SQL> insert into t values ( 1,-1);

  insert into t values ( 1,-1)

  *

  ERROR at line 1:

  ORA-02290: check constraint

  (OPS$TKYTE.CHECK_Y) violated

  前面在我提交前能执行的语句现在立即出了问题。因为我手动修改了默认的约束模式。


这里以MySQL为例,总结一下3种外键约束方式的区别和联系。 


     这里以用户表和用户组表为例,这是一个典型的多对一关系,多个用户对应于一个用户组。 
     首先创建用户组表: 
Sql代码 
  1. create table t_group (   
  2.     id int not null,   
  3.     name varchar(30),   
  4.     primary key (id)   
  5. );  
create table t_group (id int not null,name varchar(30),primary key (id));


并插入两条记录: 
Sql代码 
  1. insert into t_group values (1, 'Group1');   
  2. insert into t_group values (2, 'Group2');  
insert into t_group values (1, 'Group1');insert into t_group values (2, 'Group2');


下面创建用户表,分别以不同的约束方式创建外键引用关系: 
1、级联(cascade)方式  (级联意味着父值的变化会影响到子值)
Sql代码 
  1. create table t_user (   
  2.     id int not null,   
  3.     name varchar(30),   
  4.     groupid int,   
  5.     primary key (id),   
  6.     foreign key (groupid) references t_group(id) on delete cascade on update cascade  
  7. );  
create table t_user (id int not null,name varchar(30),groupid int,primary key (id),foreign key (groupid) references t_group(id) on delete cascade on update cascade);


参照完整性测试 
Sql代码  复制代码
  1. insert into t_user values (1, 'qianxin', 1); --可以插入   
  2. insert into t_user values (2, 'yiyu', 2);    --可以插入   
  3. insert into t_user values (3, 'dai', 3);    --错误,无法插入,用户组3不存在,与参照完整性约束不符  
insert into t_user values (1, 'qianxin', 1); --可以插入insert into t_user values (2, 'yiyu', 2);    --可以插入insert into t_user values (3, 'dai', 3);    --错误,无法插入,用户组3不存在,与参照完整性约束不符


约束方式测试 
Sql代码  复制代码
  1. insert into t_user values (1, 'qianxin', 1);   
  2. insert into t_user values (2, 'yiyu', 2);   
  3. insert into t_user values (3, 'dai', 2);   
  4. delete from t_group where id=2;              --导致t_user中的2、3记录级联删除   
  5. update t_group set id=2 where id=1;          --导致t_user中的1记录的groupid级联修改为2  
insert into t_user values (1, 'qianxin', 1);insert into t_user values (2, 'yiyu', 2);insert into t_user values (3, 'dai', 2);delete from t_group where id=2;              --导致t_user中的2、3记录级联删除update t_group set id=2 where id=1;          --导致t_user中的1记录的groupid级联修改为2


2、置空(set null)方式  
Sql代码  复制代码
  1. 置空方式   
  2. create table t_user (   
  3.     id int not null,   
  4.     name varchar(30),   
  5.     groupid int,   
  6.     primary key (id),   
  7.     foreign key (groupid) references t_group(id) on delete set null on update set null  
  8. );   
  9.   
  10. 参照完整性测试   
  11.   
  12. insert into t_user values (1, 'qianxin', 1); --可以插入   
  13. insert into t_user values (2, 'yiyu', 2);    --可以插入   
  14. insert into t_user values (3, 'dai', 3);     --错误,无法插入,用户组3不存在,与参照完整性约束不符   
  15.   
  16. 约束方式测试   
  17. insert into t_user values (1, 'qianxin', 1);   
  18. insert into t_user values (2, 'yiyu', 2);   
  19. insert into t_user values (3, 'dai', 2);   
  20. delete from t_group where id=2;              --导致t_user中的2、3记录的groupid被设置为NULL   
  21. update t_group set id=2 where id=1;          --导致t_user中的1记录的groupid被设置为NULL  
置空方式create table t_user (id int not null,name varchar(30),groupid int,primary key (id),foreign key (groupid) references t_group(id) on delete set null on update set null);参照完整性测试insert into t_user values (1, 'qianxin', 1); --可以插入insert into t_user values (2, 'yiyu', 2);    --可以插入insert into t_user values (3, 'dai', 3);     --错误,无法插入,用户组3不存在,与参照完整性约束不符约束方式测试insert into t_user values (1, 'qianxin', 1);insert into t_user values (2, 'yiyu', 2);insert into t_user values (3, 'dai', 2);delete from t_group where id=2;              --导致t_user中的2、3记录的groupid被设置为NULLupdate t_group set id=2 where id=1;          --导致t_user中的1记录的groupid被设置为NULL



3、禁止(no action / restrict)方式 
Sql代码  复制代码
  1. 禁止方式   
  2. create table t_user (   
  3.     id int not null,   
  4.     name varchar(30),   
  5.     groupid int,   
  6.     primary key (id),   
  7.     foreign key (groupid) references t_group(id) on delete no action on update no action  
  8. );   
  9.   
  10. 参照完整性测试   
  11. insert into t_user values (1, 'qianxin', 1); --可以插入   
  12. insert into t_user values (2, 'yiyu', 2);    --可以插入   
  13. insert into t_user values (3, 'dai', 3);     --错误,无法插入,用户组3不存在,与参照完整性约束不符   
  14.   
  15. 约束方式测试   
  16. insert into t_user values (1, 'qianxin', 1);   
  17. insert into t_user values (2, 'yiyu', 2);   
  18. insert into t_user values (3, 'dai', 2);   
  19. delete from t_group where id=2;              --错误,从表中有相关引用,因此主表中无法删除   
  20. update t_group set id=2 where id=1;          --错误,从表中有相关引用,因此主表中无法修改  
禁止方式create table t_user (id int not null,name varchar(30),groupid int,primary key (id),foreign key (groupid) references t_group(id) on delete no action on update no action);参照完整性测试insert into t_user values (1, 'qianxin', 1); --可以插入insert into t_user values (2, 'yiyu', 2);    --可以插入insert into t_user values (3, 'dai', 3);     --错误,无法插入,用户组3不存在,与参照完整性约束不符约束方式测试insert into t_user values (1, 'qianxin', 1);insert into t_user values (2, 'yiyu', 2);insert into t_user values (3, 'dai', 2);delete from t_group where id=2;              --错误,从表中有相关引用,因此主表中无法删除update t_group set id=2 where id=1;          --错误,从表中有相关引用,因此主表中无法修改
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值