简介这份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 insensitiveci表示 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 VIEWMySQL 没有原生物化视图得用定时任务或触发器模拟。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连接串里加characterEncodingutf8MySQL 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 可以只讲两节课但里面的东西值得反复回来翻。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?