四个判断点
先确定目标表,再确定受影响元组;然后说明变化内容和取值来源,最后检查约束能否保持
让关系实例按业务规则发生变化
INSERT、UPDATE 和 DELETE 分别增加、修改和删除关系实例中的元组
三类操作都要明确目标表、受影响元组、变化内容和约束状态
先确定目标表,再确定受影响元组;然后说明变化内容和取值来源,最后检查约束能否保持
新元组来自 VALUES 或 SELECT
目标行由 WHERE 选出,值由 SET 给出
目标行由 WHERE 选出,不产生新值
明确的属性列列表让语句不依赖表定义顺序
01
02INSERT INTO Student(Sno, Sname, Ssex, Smajor, Sbirthdate)
VALUES ('20180009', '陈冬', '男', '信息管理与信息系统', '2000-5-22');01
02
03INSERT INTO SC(Sno, Cno, Semester, Teachingclass)
VALUES ('20180009', '81004', '20202', '81004-01');
-- Grade 未提供;当前 3.2 定义没有 DEFAULT,取 NULL未列出的列有 DEFAULT 时取默认值;可空且无 DEFAULT 时取 NULL;NOT NULL 且无 DEFAULT 时会导致插入失败
INSERT ... SELECT 先形成查询结果,再按目标列把多个元组写入目标表;单独执行 SELECT 可以预览这些元组
01
02
03
04
05
06
07
08
09
10
11
12
13
14-- 先建立目标表,再执行批量插入
CREATE TABLE Smajor_age (
Smajor VARCHAR(40) NOT NULL PRIMARY KEY,
Avg_age DECIMAL(5,2)
);
-- 先单独执行下面的 SELECT,确认结果后再执行整条 INSERT
INSERT INTO Smajor_age(Smajor, Avg_age)
SELECT Smajor,
AVG(extract(year from current_date) - extract(year from Sbirthdate))
FROM Student
WHERE Smajor IS NOT NULL
AND Sbirthdate IS NOT NULL
GROUP BY Smajor;先预览查询结果,再批量写入;目标列、列数、类型与约束必须对应
新元组必须符合表定义和完整性约束
| 情况 | 结果 | 需要检查 |
|---|---|---|
| 列表中提供值 | 按列名对应写入 | 类型与业务含义 |
| 省略可空且无 DEFAULT 的列 | 取 NULL | 是否允许空值 |
| 省略 NOT NULL 且有 DEFAULT 的列 | 取 DEFAULT | 默认值定义 |
| 省略 NOT NULL 且无 DEFAULT 的列 | 插入失败 | 是否补齐必需值 |
| 主码重复或外码不存在 | DBMS 拒绝该行 | 实体与参照完整性 |
当前 3.2 的 SC.Grade 没有 DEFAULT;单行插入中省略 Grade 会取 NULL,不是 0
SET 表达新值,WHERE 确定受影响的元组
01
02
03
04
05UPDATE SC
SET Grade = Grade - 5
WHERE Semester = '20201'
AND Cno = '81002'
AND Grade IS NOT NULL;本例只调整已经录入的成绩;NULL 表示尚未录入,不参与数值减法,0—100 范围需由约束或业务条件保证
省略 WHERE 不是少写一个条件,而是选择全表更新
以主码或业务键定位一个元组
用学期、课程和状态组合出目标集合
省略 WHERE 后表中所有元组都会受影响
执行 UPDATE 前,应使用相同的 WHERE Semester = '20201' AND Cno = '81002' 做 SELECT 预览
外层更新表,内层查询负责找出符合条件的键
01
02
03
04
05
06
07UPDATE SC
SET Grade = 0
WHERE Grade IS NOT NULL
AND Sno IN
(SELECT Sno
FROM Student
WHERE Smajor = '计算机科学与技术');先运行内层 SELECT,确认它返回的键确实是要修改的对象;不要把尚未录入的 NULL 无提示地改成零分
DELETE 改变表实例,不改变表对象、列和索引的定义
01
02
03
04
05
06
07
08-- 先检查 SC 是否仍有引用记录
SELECT Sno, Cno
FROM SC
WHERE Sno = '20180007';
-- 确认按业务规则处理引用后,再判断是否删除 Student
DELETE FROM Student
WHERE Sno = '20180007';| 操作 | 删除元组 | 删除表定义 |
|---|---|---|
DELETE ... WHERE | 指定元组 | 否 |
DELETE FROM 表 | 全部元组 | 否 |
DROP TABLE | 连同对象一起移除 | 是 |
若 SC 仍引用该 Student,外码可能拒绝 DELETE;只有约束明确声明 ON DELETE CASCADE,才讨论级联处理
删除条件确定目标元组;外码引用和业务后果还需要单独检查
01
02
03
04
05DELETE FROM SC
WHERE Sno IN
(SELECT Sno
FROM Student
WHERE Smajor = '计算机科学与技术');本例删除的是 SC 子行,不删除 Student;若删除被引用的 Student,是否同步删除 SC 由外码上的 ON DELETE 规则决定
变更正确性取决于目标集合、影响范围和更新后的关系状态
先用 SELECT 预览目标集合,再估计影响行数;执行变更后复查关键列
主码唯一且不为空
外码引用有效的被参照值
业务范围和状态规则仍然成立
客户端显示的影响行数是辅助证据,不能替代变更后的 SELECT 复查
INSERT、UPDATE 和 DELETE 都要先确定目标集合,再检查约束和变更结果
INSERT 需要明确属性列,处理 DEFAULT 与 NULL,并检查 INSERT SELECT 的结果和约束
UPDATE 用 SET 表达新值,用 WHERE 或子查询确定目标集合,并防止误触发全表更新
DELETE 只删除元组;DROP TABLE 删除表对象,外码后果和 CASCADE 必须按定义确认
安全的数据更新遵循“先预览、后变更、再复查”的顺序