主键与外键的关系、级联保存、更新、删除

本文详细介绍了数据库中主键与外键的定义、关系,以及级联删除、更新的实现方式,并通过SQL示例演示了如何在实际场景中应用这些概念,确保数据一致性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主键与外键的关系、级联保存、更新、删除

http://www.alixixi.com/ePrint.asp?from=dev&id=34852

 

正文:
--建立数据库
create database test;
go

--建立表customers
create table customers(
id int identity(1,1) not null,
name varchar(15),
age int,
primary key(id)
);
go

--建立表orders
create table orders(
id int identity(1,1) not null,
order_number varchar(15),
price money,
customer_id int,
primary key(id)
);
go

--对表orders插入数据,以检测money数据类型,结果为:69.0000
insert into orders(price) values(69);
select * from orders;

--增加外键与关系约束
alter table orders add constraint FK_CUSTOMER foreign key (customer_id) references customers(id);
go

--级联删除、更新
alter table orders add constraint FK_CUSTOMER foreign key (customer_id) references customers(id)
on delete cascade on update cascade;
go

--级联删除
alter table orders add constraint FK_CUSTOMER foreign key (customer_id) references customers(id)
on delete cascade;
go
=====================================================================================================
--
insert into customers values('张三',25);
insert into customers values('李四',25);

--如果设置了级联插入,那么在向子表orders插入的customer_id(外键)
--必须在父表customers中存在此id(主键)
insert into orders values(1,50,5);

--如果设置了级联删除,删除父表customers中id=5的记录,
--也会删除子表orders中customer_id=5的记录,
delete from customers where id=5


--查询
select * from customers;
select * from orders

 

 

 

SQL主键和外键的删除规则说明

http://www.hake.cc/a/shujuku/mssql/2011/0918/21683.html

 

 

SQL表中经常包含外键关系,删除一个表的数据就会影响其他的表,下面将为您介绍SQL主键和外键的删除规则说明,供您参考,希望对您有所帮助。

删除规则和更新规则:
指定当数据库的最终用户尝试删除或更新某一行,而该行包含外键关系所涉及的数据时所发生的情况。

如果设置为:

 

无操作:当在删除或更新主键表的数据时,将显示一条错误信息,告知用户不允许执行该删除或更新操作,删除或更新操作将会被回滚。

 

层叠:删除或更新包含外键关系中所涉及的数据的所有行。
说明:“层叠”在SQL server 2000中又叫“级联”。

 

设置空:这是SQL server 2005新增的功能。如果表的所有外键列都可以接受空值,则将该值设置为空。
说明:要将外键的删除规则和更新规则设为“设置空”,则该外键必须是可以为空的字段。

 

设置默认值:这是SQL server 2005新增的功能。如果表的所有外键列都已定义了默认值,则将该值设置为该列定义的默认值。
说明:要将外键的删除规则和更新规则设置为“设置默认值”,该外键必须是有默认值的字段。

附加:

 

SQLServer2005

http://blog.sina.com.cn/s/blog_707a4cbf0100qz6c.html

表T_Device:

DeviceID(主键)

TypeID(外键,引用到T_Type表的TypeID字段)

表T_Type:

TypeID(主键)

如图:

在表设计器里面T_Device表的TypeID字段右键单击,弹出菜单上选择关系,如图:

在弹出的外键关系对话框中的INSERT和UPDATE规范中

更新规则:层叠(默认为无操作)

删除规则:层叠(默认为无操作)

可以实现级联操作

如图:

 

这时删除表T_Type表中的一条记录,会自动删除T_Device表中对应的记录集,例如如下关系:

T_Device:

DeviceID        TypeID

1                      3

2                      1

3                      1

4                      2

5                      1

T_Type:

TypeID

1

2

3

删除T_Type表中TypeID为1的记录的时候,T_Device表中的对应的TypeID为1的记录集都会被删除。

 

下面的理解是错误的:

删除T_Device表中的一条记录会对应删除T_Type表中对应的记录,例如,删除T_Device表中TypeID为3的那条记录,会级联删除T_Type表中的TypeID为3的记录。

这种理解的错误在于,如果删除T_Device表中TypeID为1的一条记录(如语句delete from table T_Device where DeviceID = 2),那么如果对应的T_Type表中的TypeID为1的记录被删除了,则T_Device表中DeviceID为3和5的记录对应的TypeID就失效了,这样破坏了外键关联的正确性。

这种理解错误的根源在于没有搞清楚外键两边谁是引用,谁是实体,也没有搞清楚级联删除的意义在于除实体的时候级联的删除其所有引用的问题。

在上述例子中对于T_Device表来讲,T_Type表中的记录为实体,T_Device表中的TypeID字段为引用

 

另外,外键约束保证了数据的逻辑完整性,级联操作只适用于主表(或被引用表)的删除(delete)和更新(Update)操作,

不适用于从表(或引用表)的插入(Insert)操作,因此不要想象如下代码可以被执行:

insert into T_Device values(1,3); 错错错,这个是可以执行的,实例验证

T_Type表里面只要有相应的数据就可以执行

如果认为在T_Device表中插入一条记录的同时,在T_Type表中会插入相应的被关联到T_Device表的记录是不对的,因为如果再执行insert into dev values(2,3);会如何呢?T_Type表中难道会存在两条TypeID为3的记录吗,这样违背了主键唯一性,因此做插入操作只能是先插入主表(或被引用表),然后插入从表(引用表)。

保存的时候先保存T_Type表,记得一定要保存表,否则主键个外键关系实际是没有创建的


MySQL中利用外键实现级联删除、更新

http://linghongli.iteye.com/blog/649796
MySQL支持外键的存储引擎只有InnoDB,在创建外键的时候,要求父表必须有对应的索引,子表在创建外键的时候也会自动创建对应的索引。在创建索引的时候,可以指定在删除、更新父表时,对子表进行的相应操作,包括RESTRICT、NO ACTION、SET NULL和CASCADE。其中RESTRICT和NO ACTION相同,是指在子表有关联记录的情况下父表不能更新CASCADE表示父表在更新或者删除时,更新或者删除子表对应记录;SET NULL则是表示父表在更新或者删除的时候,子表的对应字段被SET NULL。
因为只有InnoDB引擎才允许使用外键,所以,我们的数据表必须使用InnoDB引擎。我所使用的版本是Mysql5.1版本的,过程如下:
创建数据库:
Create database test;
创建两个表,其中第一个表的”id”是第二个表(userinfo)的外键:
CREATE TABLE `user` (
`id` int(4) NOT NULL,
`sex` enum('f','m') DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `userinfo` (
`sn` int(4) NOT NULL AUTO_INCREMENT,
`userid` int(4) NOT NULL,
`info` varchar(20) DEFAULT NULL,
PRIMARY KEY (`sn`),
KEY `userid` (`userid`),
CONSTRAINT `userinfo_ibfk_1` FOREIGN KEY (`userid`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
注意:
1、存储引擎必须使用InnoDB引擎;
2、外键必须建立索引;
3、外键绑定关系这里使用了“ ON DELETE CASCADE ” “ON UPDATE CASCADE”,意思是如果外键对应数据被删除或者更新时,将关联数据完全删除或者相应地更新。更多信息请参考MySQL手册中关于InnoDB的文档;
好,接着我们再来插入数据测试:
INSERT INTO `user` (`id`,`sex`)
VALUES ('1', 'f'), ('2', 'm'), ('3', 'f');
INSERT INTO `userinfo` (`sn`,`userid`,`info`)
VALUES ('1', '1', '2005054dsf'),
('2', '1', 'fdsfewfdsfds'),
('3', '1', 'gdsgergergrtre'),
('4', '2', 'et34t5435435werwe'),
('5', '2', '435rtgtrhfghfg'),
('6', '2', 'ret345tr4345'),
('7', '3', 'fgbdfvbcbfdgr'),
('8', '3', '45r2343234were'),
('9', '3', 'wfyhtyjtyjyjy');
我们先看一下当前数据表的状态:
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| user |
| userinfo |
+----------------+
2 rows in set (0.00 sec)
User表中的数据:
mysql> select * from user;
+----+------+
| id | sex |
+----+------+
| 1 | f |
| 2 | m |
| 3 | f |
+----+------+
3 rows in set (0.00 sec)
Userinfo表中的数据:
mysql> select * from userinfo;
+----+--------+-------------------+
| sn | userid | info |
+----+--------+-------------------+
| 1 | 1 | 2005054dsf |
| 2 | 1 | fdsfewfdsfds |
| 3 | 1 | gdsgergergrtre |
| 4 | 2 | et34t5435435werwe |
| 5 | 2 | 435rtgtrhfghfg |
| 6 | 2 | ret345tr4345 |
| 7 | 3 | fgbdfvbcbfdgr |
| 8 | 3 | 45r2343234were |
| 9 | 3 | wfyhtyjtyjyjy |
+----+--------+-------------------+
9 rows in set (0.00 sec)
对于建立以上不表,相信对大家也没什么难度了。好的,下面我们就要试验我们的级联删除功能了。
我们将删除user表中id为2的数据记录,看看userinf表中userid为2的相关子纪录是否会自动删除:
执行删除操作成功!
mysql> delete from `user` where `id`='2';
Query OK, 1 row affected (0.03 sec)
看看user表中已经没有id为2的数据记录了!
mysql> select * from user;
+----+------+
| id | sex |
+----+------+
| 1 | f |
| 3 | f |
+----+------+
2 rows in set (0.00 sec)
再看看userinfo表中已经没有userid为2的3条数据记录了,对应数据确实自动删除了!
mysql> select * from userinfo;
+----+--------+----------------+
| sn | userid | info |
+----+--------+----------------+
| 1 | 1 | 2005054dsf |
| 2 | 1 | fdsfewfdsfds |
| 3 | 1 | gdsgergergrtre |
| 7 | 3 | fgbdfvbcbfdgr |
| 8 | 3 | 45r2343234were |
| 9 | 3 | wfyhtyjtyjyjy |
+----+--------+----------------+
6 rows in set (0.00 sec)
更新的操作也类似,因为我们在前面建表的时候已经定义外键删除、更新操作都是CASCADE,所以在这里可以直接测试数据。
将user表中原来id为1的数据记录更改为id为4,执行如下:
mysql> update user set id=4 where id='1';
Query OK, 1 row affected (0.03 sec)
Rows matched: 1 Changed: 1 Warnings: 0
现在去看看两个表中是数据是否发生了变化:
mysql> select * from user;
+----+------+
| id | sex |
+----+------+
| 3 | f |
| 4 | f |
+----+------+
2 rows in set (0.00 sec)
mysql> select * from userinfo;
+----+--------+----------------+
| sn | userid | info |
+----+--------+----------------+
| 1 | 4 | 2005054dsf |
| 2 | 4 | fdsfewfdsfds |
| 3 | 4 | gdsgergergrtre |
| 7 | 3 | fgbdfvbcbfdgr |
| 8 | 3 | 45r2343234were |
| 9 | 3 | wfyhtyjtyjyjy |
+----+--------+----------------+
6 rows in set (0.00 sec)
比较原来的表可以发现它们的确已经更新成功了,测试完成!!!这也就实现了用外键对多个相关联的表做同时删除、更新的操作,从而保证了数据的一致性。 
 

 

<think>好的,用户想了解在SQLite中如何使用主键以及级联操作。首先,我需要回顾之前提供的回答,确保这次回答保持一致。用户提到了主键级联删除更新,所以需要覆盖这些方面。 根据用户提供的引用,特别是引用[1]提到SQLite默认关闭,需要先启用。所以第一步应该说明开启支持的方法,使用PRAGMA foreign_keys = ON。这点很重要,否则用户可能遇到不生效的问题。 接下来是创建主键。SQLite中的主键可以通过在列定义时使用PRIMARY KEY,或者创建表时指定。需要区分单列主键和联合主键的情况。例如,单列主键可以直接在列后加PRIMARY KEY,而联合主键需要在CREATE TABLE语句末尾用PRIMARY KEY (col1, col2)。 然后是的设置。需要强调被引用的列必须有唯一性约束,如主键或UNIQUE约束。用户提供的示例中,parent表的id是主键且UNIQUE,所以在child表中可以引用。如果引用的是非主键列,必须确保该列有UNIQUE约束或索引。 级联操作部分,用户提到了级联删除更新。需要详细说明ON DELETE CASCADE和ON UPDATE CASCADE的用法,以及它们的作用。例如,当父表的记录被删除更新时,子表的相应记录会自动处理。同时,需要提醒用户级联操作的风险,比如级联删除可能导致数据意丢失,建议谨慎使用。 用户可能遇到的常见问题,比如未启用导致约束失效,或者忘记为被引用列添加唯一约束。需要给出验证方法,例如检查是否启用,或者查询表的索引信息。此,复合的情况也需要说明,确保所有列对应父表的列组合有唯一性。 还要考虑不同数据库的差异,但用户特别询问SQLite,所以可以专注于SQLite的特性。例如,SQLite的支持需要显式启用,而其他数据库如MySQL可能默认开启。同时,SQLite的级联操作选项其他数据库类似,但实现细节可能有差异。 最后,用户可能需要具体的代码示例来参考。根据引用中的例子,可以构造一个完整的示例,包括创建父表和子表,启用,设置级联操作。同时,展示如何插入数据和测试级联效果,帮助用户理解实际应用。 总结步骤应该是:启用支持、创建主键、设置约束、定义级联操作,以及注意事项和常见问题解决。这样结构清晰,用户能一步步跟着操作。此,生成相关问题可以帮助用户进一步学习,如约束的验证方法或复合的使用。</think>#### 一、SQLite基础设置 1. **启用支持** ```sql PRAGMA foreign_keys = ON; -- 必须显式开启(每个连接都需要执行)[^1] ``` 2. **主键定义规范** - 单列主键: ```sql CREATE TABLE Parent ( id TEXT PRIMARY KEY NOT NULL UNIQUE -- 主键自动包含UNIQUE约束 ); ``` - 联合主键: ```sql CREATE TABLE CompositeKeyDemo ( col1 TEXT, col2 INTEGER, PRIMARY KEY (col1, col2) -- 联合主键定义 ); ``` #### 二、级联操作实现 1. **基础配置** ```sql CREATE TABLE Child ( child_id INTEGER PRIMARY KEY, parent_id TEXT, FOREIGN KEY (parent_id) REFERENCES Parent(id) ON DELETE CASCADE -- 级联删除 ON UPDATE CASCADE -- 级联更新[^4] ); ``` 2. **级联操作类型** | 操作类型 | 效果描述 | |---------------|------------------------------------------------------------------------| | `ON DELETE CASCADE` | 父表记录删除时自动删除子表关联记录[^2] | | `ON UPDATE CASCADE` | 父表主键更新时自动更新子表值(需引用主键列)[^4] | | `ON DELETE SET NULL` | 父表删除时子表设为NULL(要求列允许NULL) | #### 三、完整实现示例 ```sql -- 启用支持 PRAGMA foreign_keys = ON; -- 创建父表 CREATE TABLE Business ( ID TEXT PRIMARY KEY NOT NULL UNIQUE, Name TEXT NOT NULL, Parent_ID TEXT, -- 自引用 FOREIGN KEY (Parent_ID) REFERENCES Business(ID) ON DELETE CASCADE ON UPDATE CASCADE ); -- 创建子表 CREATE TABLE Employee ( emp_id INTEGER PRIMARY KEY, business_id TEXT NOT NULL, FOREIGN KEY (business_id) REFERENCES Business(ID) ON DELETE CASCADE -- 删除公司时自动删除员工 ON UPDATE SET NULL -- 公司ID更新时员工business_id置空 ); ``` #### 四、核心注意事项 1. **有效性验证** ```sql PRAGMA foreign_key_check; -- 检测约束违反 PRAGMA foreign_key_list(Employee); -- 查看表的配置 ``` 2. **级联更新限制** - 仅当引用主键列时,`ON UPDATE CASCADE`才能生效[^4] - 更新后的主键值必须保持唯一性 3. **删除顺序控制** - 删除父表前需先删除子表,或使用`DROP TABLE ... CASCADE`(SQLite 3.35+) #### 五、常见问题解决方案 1. **错误:`foreign key mismatch`** - 检查父子表字段类型是否完全一致 - 验证被引用字段是否有`UNIQUE`约束 2. **级联失效排查** ```sql -- 确认支持已启用 PRAGMA foreign_keys; -- 检查索引状态 SELECT * FROM pragma_index_list('Parent'); SELECT * FROM pragma_index_info('sqlite_autoindex_Parent_1'); ``` #### 六、性能优化建议 1. **索引策略** - 为所有列创建索引 ```sql CREATE INDEX idx_employee_business ON Employee(business_id); ``` 2. **批量操作优化** ```sql BEGIN TRANSACTION; UPDATE Parent SET id = 'new_id' WHERE id = 'old_id'; DELETE FROM Parent WHERE id = 'expired_id'; COMMIT; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值