简介:这份PPT课件面向高校计算机及相关专业学生,聚焦《数据库系统概论》第4章“关系数据库标准语言——SQL语言”的第一部分内容,帮助读者系统掌握SQL的核心概念与基础语法。课件从SQL概述切入,讲解其一体化、非过程化、面向集合等语言特点,并梳理数据定义、数据操纵、数据查询、数据控制等分类框架,随后重点展开数据定义部分,涵盖基本表的创建、修改与删除,以及主键、外键、非空、唯一、检查等完整性约束的用法,配合职工、部门等关系模式建表实例,便于对照理解。资源包内含1个PPT文件,大小约428KB,以图文与代码示例结合的方式呈现,适合课堂讲授、期末复习或自学梳理知识脉络。目前已有100人学习,可作为SQL入门阶段快速建立整体认知的参考材料。
1. 从一份 PPT 说起:关系数据库标准语言 SQL 到底在讲什么
很多人第一次接触《数据库系统概论》第 4 章,是在课堂上对着一份 SQL 语言 PPT 昏昏欲睡。但真正到了工作里,你会发现这一章几乎是所有数据相关岗位的“入场券”——不管你是写后端、做数据分析,还是搞数据仓库,每天敲的SELECT、INSERT、UPDATE、DELETE,根子都在这里。这份 PPT 的核心,是把关系数据库标准语言 SQL 的骨架讲清楚:数据定义、数据查询、数据更新、视图与权限控制。它解决的不是“怎么写一个能跑的 SQL”,而是“为什么 SQL 长这样、什么时候该用哪种写法、不同数据库之间到底差在哪”。适合刚学完关系模型、准备动手建库建表的人,也适合写了几年 SQL 却一直靠试错、没系统梳理过标准语法边界的从业者。下面我按自己带新人和做项目的顺序,把这一章拆成能直接上手复现的路径。
2. SQL 的四个子语言:先分清 DDL、DML、DQL、DCL 再动手
2.1 为什么一上来就要分子语言
关系数据库标准语言 SQL 不是铁板一块。标准里把它按功能分成几类,最常见的分法是数据定义(DDL)、数据操纵(DML)、数据查询(DQL)、数据控制(DCL)。很多人写 SQL 出问题,不是语法不会,而是没意识到自己正在跨层操作。比如在 DDL 里想加WHERE,在 DQL 里想改表结构,方向一开始就错了。
DDL 负责“房子怎么盖”:CREATE、ALTER、DROP、TRUNCATE。DML 负责“家具怎么搬”:INSERT、UPDATE、DELETE。DQL 负责“怎么看”:SELECT。DCL 负责“谁能进哪个房间”:GRANT、REVOKE。这份 PPT 第 4 章通常先讲 DDL 再讲 DQL,顺序是有道理的——没有表,查询无从谈起。
我一般会让新人先记住一句话:DDL 改结构,DML 改数据,DQL 读数据,DCL 改权限。四类语句在事务里的行为也不一样,DDL 在很多数据库里是隐式提交的,不能随便回滚,这一点后面避坑章节会细说。
2.2 用一条最小命令把 DDL 跑通
先建一个能用的库和表,别一上来就设计十几张表的电商模型。下面这段在 MySQL 8.x 和 PostgreSQL 里基本通用,差异我会标出来。
-- 建库,字符集用 utf8mb4,避免中文和 emoji 翻车 CREATE DATABASE IF NOT EXISTS demo_sql DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_0900_ai_ci; -- PostgreSQL 没有这句,用 ENCODING 'UTF8' -- 切库 USE demo_sql; -- PostgreSQL 用 \c demo_sql -- 建学生表,主键自增 CREATE TABLE student ( sno CHAR(8) NOT NULL, -- 学号,定长 sname VARCHAR(20) NOT NULL, -- 姓名,变长 sage SMALLINT DEFAULT NULL, -- 年龄 sdept VARCHAR(30) DEFAULT NULL, -- 系别 PRIMARY KEY (sno) ); -- 建选课表,复合主键 + 外键 CREATE TABLE sc ( sno CHAR(8) NOT NULL, cno CHAR(4) NOT NULL, grade DECIMAL(5,1) DEFAULT NULL, PRIMARY KEY (sno, cno), CONSTRAINT fk_sc_student FOREIGN KEY (sno) REFERENCES student(sno) );逻辑说明:CREATE DATABASE指定字符集是关键,很多中文乱码问题在这一步就埋下了。CHAR(8)和VARCHAR(20)的选择不是随便写的,学号长度固定用CHAR更省空间,姓名长度不定用VARCHAR。DECIMAL(5,1)表示总共 5 位、小数点后 1 位,成绩用这个比FLOAT稳,不会出现59.999999这种玄学。
参数说明:utf8mb4_0900_ai_ci是 MySQL 8 的默认排序规则,ai表示 accent insensitive,ci表示 case insensitive。如果你的库要区分大小写,得换成_bin或_cs结尾的排序规则。PostgreSQL 建库时用ENCODING 'UTF8',排序规则在列级别或库级别单独指定。
2.3 DML 和 DQL 的最小闭环
建完表要能塞数据、查出来,才算跑通。下面这段把插入、更新、删除、查询串成一个闭环。
-- 插入:显式列出列名,别依赖列顺序 INSERT INTO student (sno, sname, sage, sdept) VALUES ('20240001', '张三', 20, '计算机系'), ('20240002', '李四', 21, '软件工程'), ('20240003', '王五', 19, '计算机系'); INSERT INTO sc (sno, cno, grade) VALUES ('20240001', 'C001', 88.5), ('20240001', 'C002', 92.0), ('20240002', 'C001', 76.0); -- 查询:查计算机系年龄大于 19 的学生 SELECT sno, sname, sage FROM student WHERE sdept = '计算机系' AND sage > 19 ORDER BY sage DESC; -- 更新:给指定学号改系别 UPDATE student SET sdept = '人工智能系' WHERE sno = '20240003'; -- 删除:删掉某条选课记录 DELETE FROM sc WHERE sno = '20240002' AND cno = 'C001';逻辑说明:INSERT显式写列名是血泪经验,一旦表结构加了列,不写列名的插入会直接报错或插错位置。WHERE条件在UPDATE和DELETE里是后悔药,没有WHERE的UPDATE会更新全表,没有WHERE的DELETE会清空全表,这两条命令在生产环境里翻车的人不在少数。
参数说明:ORDER BY sage DESC里的DESC是降序,默认是ASC升序。DECIMAL(5,1)插入88.5没问题,插入88.55会被四舍五入成88.6,这是精度约束决定的,不是 bug。
3. 单表查询到多表连接:把 SELECT 的执行顺序吃透
3.1 SELECT 不是按书写顺序执行的
这是关系数据库标准语言 SQL 里最容易被忽略、又最影响性能的一点。你写的顺序是SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ...,但数据库实际执行顺序大致是:FROM→WHERE→GROUP BY→HAVING→SELECT→ORDER BY→LIMIT。
理解这个顺序,很多“为什么别名在 WHERE 里不能用”“为什么 HAVING 能过滤聚合结果而 WHERE 不能”的问题就自动解开了。因为WHERE执行时SELECT还没跑,别名还没生成;HAVING在GROUP BY之后执行,所以能对聚合函数的结果做过滤。
我一般会拿这个例子让人自己推一遍:
SELECT sdept, COUNT(*) AS cnt, AVG(sage) AS avg_age FROM student WHERE sage IS NOT NULL GROUP BY sdept HAVING COUNT(*) >= 2 ORDER BY cnt DESC;逻辑说明:WHERE sage IS NOT NULL在分组前过滤掉年龄为空的记录,GROUP BY sdept按系别分组,HAVING COUNT(*) >= 2过滤掉人数少于 2 的系,ORDER BY cnt DESC按人数降序。如果把COUNT(*) >= 2写到WHERE里,直接报错,因为那时还没分组。
参数说明:COUNT(*)统计所有行,COUNT(sage)只统计sage非空的行,两者在有空值时结果不同。AVG(sage)会自动忽略NULL,但分母是sage非空的行数,不是总行数,这个细节在做报表时经常被误用。
3.2 多表连接的三种写法和适用场景
连接是 SQL 查询的分水岭。PPT 里通常讲等值连接、自然连接、外连接。落到实操,我把它归成三类:内连接、左/右外连接、全外连接。
-- 内连接:只返回两表都匹配的行 SELECT s.sname, sc.cno, sc.grade FROM student s INNER JOIN sc ON s.sno = sc.sno WHERE sc.grade >= 80; -- 左外连接:保留左表所有行,右表没匹配的补 NULL SELECT s.sname, sc.cno, sc.grade FROM student s LEFT JOIN sc ON s.sno = sc.sno; -- 右外连接:保留右表所有行 SELECT s.sname, sc.cno, sc.grade FROM student s RIGHT JOIN sc ON s.sno = sc.sno;逻辑说明:内连接是默认连接,INNER可以省略。左外连接用来查“哪些学生没选课”,因为没选课的学生在sc表里没有记录,内连接会把他们过滤掉,左外连接会保留他们,cno和grade显示为NULL。右外连接在实际项目里用得少,因为把表顺序换一下就能用左外连接表达,可读性更好。
参数说明:ON后面跟连接条件,WHERE后面跟过滤条件。在外连接里,ON和WHERE的位置会影响结果:把右表的过滤条件写在ON里,左表不匹配的行仍然保留;写在WHERE里,NULL行会被过滤掉,外连接退化成内连接。这是外连接最常见的坑。
3.3 子查询和 EXISTS 的取舍
子查询能解决的问题,连接基本都能解决,但有些场景子查询更直观。比如“查选了 C001 课程的学生姓名”:
-- 用 IN 子查询 SELECT sname FROM student WHERE sno IN (SELECT sno FROM sc WHERE cno = 'C001'); -- 用 EXISTS 相关子查询 SELECT sname FROM student s WHERE EXISTS (SELECT 1 FROM sc WHERE sc.sno = s.sno AND sc.cno = 'C001'); -- 用连接 SELECT DISTINCT s.sname FROM student s JOIN sc ON s.sno = sc.sno WHERE sc.cno = 'C001';逻辑说明:三种写法结果一样,但执行计划可能不同。IN子查询适合子查询结果集小的情况,EXISTS适合外层表小、内层表大的情况,连接则更通用。现代优化器对这三者的优化已经很强,但数据量上千万时差异会显现出来。
参数说明:EXISTS只关心子查询有没有返回行,SELECT 1里的1换成*或任何常量都不影响结果,写1只是习惯。DISTINCT在连接写法里是必须的,因为一个学生选多门课时会出现重复姓名,子查询写法天然去重。
4. 视图、索引与权限:把 SQL 从能跑变成能维护
4.1 视图不是表,但用好了能省很多事
视图是一张虚拟表,不存数据,只存查询定义。它的价值在于简化复杂查询、控制列级权限、屏蔽底层表结构变化。
-- 建一个只暴露姓名、课程、成绩的视图 CREATE VIEW v_student_grade AS SELECT s.sno, s.sname, sc.cno, sc.grade FROM student s JOIN sc ON s.sno = sc.sno; -- 查视图和查表一样 SELECT * FROM v_student_grade WHERE grade >= 90; -- 改视图定义用 CREATE OR REPLACE CREATE OR REPLACE VIEW v_student_grade AS SELECT s.sno, s.sname, s.sdept, sc.cno, sc.grade FROM student s JOIN sc ON s.sno = sc.sno;逻辑说明:视图定义里用了连接,查询时数据库会把视图定义展开成底层查询再执行。CREATE OR REPLACE在 MySQL 和 PostgreSQL 里都支持,改视图不用先DROP。视图的更新(INSERT/UPDATE/DELETE)有条件限制,一般只有单表、不含聚合和DISTINCT的视图才能更新,多表连接视图通常只读。
参数说明:视图不加速查询,它只是语法糖。如果底层查询慢,查视图一样慢。想加速得靠索引或物化视图,物化视图在 PostgreSQL 里用CREATE MATERIALIZED VIEW,MySQL 没有原生物化视图,得用定时任务或触发器模拟。
4.2 索引:建对了是加速,建错了是负担
索引是 SQL 性能里绕不开的话题。PPT 第 4 章可能只提一句,但实操里这是重点。
-- 在 student 表的 sname 上建普通索引 CREATE INDEX idx_student_sname ON student(sname); -- 在 sc 表的 sno 和 cno 上建复合索引 CREATE INDEX idx_sc_sno_cno ON sc(sno, cno); -- 查看查询是否走索引 EXPLAIN SELECT * FROM student WHERE sname = '张三';逻辑说明:EXPLAIN是排查慢查询的第一步,看type列,ALL是全表扫描,ref或range是走了索引。复合索引(sno, cno)能加速WHERE sno = ?和WHERE sno = ? AND cno = ?,但加速不了WHERE cno = ?,因为最左前缀原则。
参数说明:索引不是越多越好,每个索引都会增加写入成本。INSERT、UPDATE、DELETE都要维护索引,写多读少的表要控制索引数量。区分度低的列(比如性别只有男女)建索引意义不大,优化器可能直接忽略。
4.3 权限控制:GRANT 和 REVOKE 的最小用法
DCL 在实际项目里常被忽略,但生产环境必须管。
-- 创建用户并授权 CREATE USER 'app_user'@'%' IDENTIFIED BY 'StrongPass123!'; GRANT SELECT, INSERT, UPDATE ON demo_sql.* TO 'app_user'@'%'; -- 收回删除权限 REVOKE DELETE ON demo_sql.* FROM 'app_user'@'%'; -- 查看权限 SHOW GRANTS FOR 'app_user'@'%';逻辑说明:应用账号一般只给SELECT、INSERT、UPDATE,不给DELETE和DROP,删除操作通过软删除字段实现。'%'表示允许从任意主机连接,生产环境应限制具体 IP 段。
参数说明:IDENTIFIED BY后面的密码要符合数据库的密码策略,MySQL 8 默认要求大小写字母、数字、特殊字符组合。FLUSH PRIVILEGES在直接用GRANT语句时不需要,只有直接改权限表时才需要。
5. SQL 上手避坑:5 个我见过太多次的翻车现场
5.1 现象:UPDATE 没加 WHERE,全表数据被改
原因:写完UPDATE student SET sdept = '计算机系'直接回车,忘了WHERE。解决:生产环境执行UPDATE和DELETE前,先用同样的WHERE条件跑一遍SELECT COUNT(*),确认影响行数。另外,很多客户端有安全模式,可以强制要求WHERE或LIMIT,建议打开。
5.2 现象:中文插入后显示乱码或问号
原因:建库或建表时字符集不是utf8mb4,或者连接字符集没设对。解决:建库用utf8mb4,连接串里加characterEncoding=utf8,MySQL 8 驱动一般用utf8mb4。已经建错的表用ALTER TABLE ... CONVERT TO CHARACTER SET utf8mb4修,但已有数据可能已经损坏,需要重新导入。
5.3 现象:外连接查出来的结果和预期不符,NULL 行消失了
原因:把右表的过滤条件写在了WHERE里,而不是ON里。解决:外连接中,对保留侧表的过滤写在WHERE,对被保留侧表的过滤写在ON。拿不准时把条件挪到ON里试一次,对比结果。
5.4 现象:GROUP BY 查询报错,说列不在 GROUP BY 中
原因:SELECT里出现了既不在GROUP BY里、也没被聚合函数包裹的列。MySQL 5.7 之前默认允许这种写法,8.0 默认禁止。解决:要么把该列加进GROUP BY,要么用ANY_VALUE()包起来(MySQL),要么改查询逻辑。这个报错是好事,它防止了不确定的聚合结果。
5.5 现象:建了索引但查询还是慢
原因:查询条件没用到索引的最左前缀,或者对索引列做了函数运算、隐式类型转换。解决:用EXPLAIN看执行计划,确认key列有值。避免WHERE YEAR(create_time) = 2024这种写法,改成WHERE create_time >= '2024-01-01' AND create_time < '2025-01-01'。字符串列和数字比较时,确保类型一致,否则索引失效。
6. 把第 4 章学成自己的东西:一个验证清单和长期习惯
学完关系数据库标准语言 SQL 这一章,怎么判断自己是真的会了,而不是背下了语法?我一般用下面这个清单自测,你也可以拿去用。
| 验证项 | 达标标准 | 常见不达标表现 |
|---|---|---|
| DDL | 能独立设计三张以上关联表并建索引 | 建表不写主键、外键、字符集 |
| DQL 单表 | 能说清 WHERE/GROUP BY/HAVING 执行顺序 | 别名写在 WHERE 里报错 |
| DQL 多表 | 能区分内连接和外连接,知道 ON 和 WHERE 的区别 | 外连接结果不对但找不到原因 |
| 子查询 | 能写出 IN、EXISTS、连接三种等价写法 | 只会一种,换场景就卡 |
| 视图 | 能建视图并说清它不加速查询 | 以为视图能提升性能 |
| 索引 | 能用 EXPLAIN 判断是否走索引 | 建了索引但不会验证 |
| 权限 | 能给应用账号授最小权限 | 直接用 root 跑应用 |
这个清单不用一次全过,但每过一项,你在项目里的底气就多一分。我自己的习惯是:每次写完一条稍微复杂的 SQL,先EXPLAIN看一眼,再想想有没有更清晰的写法。这个习惯坚持几年,比刷多少道 SQL 题都管用。第 4 章的 PPT 可以只讲两节课,但里面的东西值得反复回来翻。希望帮到你。
本文还有配套的精品资源,点击获取