简介:这份PDF资料是B站Mosh老师三小时SQL入门课程的配套笔记,面向零基础或希望系统梳理SQL语法的开发者与数据分析初学者,帮助其快速建立关系型数据库查询的知识框架。压缩包内共1个PDF文件,约2.43MB,内容以速查手册形式组织,涵盖SELECT子句、WHERE条件筛选、AND/OR/NOT逻辑操作符、IN列表匹配、BETWEEN范围判断、LIKE模糊查询与REGEXP正则匹配,并延伸至IS NULL、ORDER BY排序、LIMIT限制、内外连接、USING与交叉连接、UNION合并及数据插入等常用语法,配有简洁示例便于对照查阅。目前已有981人学习下载,适合作为课程复习提纲或日常写查询时的随手参考,帮助读者在较短时间内掌握核心语句写法并理解各操作符的适用场景。
1. 三小时 SQL 速通地图:先看清这门语言到底由哪几块拼成
很多人学 SQL 的第一反应是背语法,背到JOIN就卡住,背到REGEXP就放弃。其实这门语言的结构比想象中规整:一条查询语句从SELECT出发,经过WHERE过滤、ORDER BY排序、LIMIT截断,再往外扩展到多表JOIN和UNION,最后落到INSERT写入。Mosh 那套三小时课程笔记之所以被反复传阅,就是因为它把这条主线压成了一张可以随身带的地图,而不是把几十个关键字平铺给你。这份笔记适合两类人:一类是刚接触数据库、需要一份能对照敲的骨架;另一类是学过一遍但知识点散落、想重新串成体系的人。下面按「基础查询 → 过滤与匹配 → 多表与集合 → 写入」四段推进,中间单独拎出易错点,最后给一份可执行的复习清单。
2. 基础查询骨架:SELECT、表达式与结果集控制
2.1 一条语句的固定顺序与大小写问题
SQL 不是大小写敏感的语言,select和SELECT在 MySQL 里等价,但习惯上关键字大写、表名列名小写,读起来层次清楚。真正需要记住的是书写顺序和执行顺序的差别:你写的是SELECT ... FROM ... WHERE ... ORDER BY ... LIMIT,而数据库内部先定位表、再过滤行、再排序、最后截断。这个差别直接决定了后面LIMIT和ORDER BY配合时的行为。
-- 基础骨架:选库、选表、过滤、排序、截断 USE sql_store; SELECT * FROM customers WHERE state = 'CA' ORDER BY first_name LIMIT 3;USE指定当前操作的数据库,SELECT *表示取全部列,WHERE过滤满足条件的行,ORDER BY按指定列排序,LIMIT 3只返回前三条。参数上唯一容易忽略的是分号:MySQL 里每条语句必须以分号结束,漏掉分号在命令行里会一直等你输入,看起来像卡死,其实是语句没闭合。
2.2 表达式列与 DISTINCT 去重
SELECT后面不只能跟列名,还能跟表达式。笔记里用points * 10 + 20演示了运算优先级:先括号,再乘除,后加减。给表达式起别名用AS,别名会成为结果集的列头,后续排序或程序取值都靠它。
-- 表达式列 + 别名,别名决定结果集列名 SELECT (points * 10 + 20) AS discount_factor FROM customers; -- DISTINCT 作用于整行组合,不是单列 SELECT DISTINCT state FROM customers;这里有个常被误解的点:DISTINCT去重的是「选出来的整行组合」,不是某一列。只选state时看起来像按州去重,一旦你写成SELECT DISTINCT state, city,去重单位就变成州加城市的组合,结果行数会明显变多。复习时把这条记成「DISTINCT 看的是投影后的整行」,比背定义管用。
2.3 ORDER BY 的多列排序与 LIMIT 的偏移写法
排序默认升序,降序要显式写DESC。多列排序的规则是:前一列相等时才看后一列,所以列的顺序就是优先级。
-- 先按州升序,州相同再按名字降序 SELECT * FROM customers ORDER BY state, first_name DESC; -- 跳过前 6 条,取 3 条 SELECT * FROM customers LIMIT 6, 3;LIMIT 6, 3这种写法第一个数是偏移量、第二个数是条数,和LIMIT 3 OFFSET 6等价。分页场景里偏移量会随页码增长,深分页时性能会下降,这是后面进阶要补的点,但在三小时课程的范围内,先把「偏移在前、条数在后」记牢,别把两个数写反——写反了结果不报错,只是数据不对,属于典型的静默翻车。
3. 过滤与匹配:WHERE 子句下的六种筛选武器
3.1 比较运算符与逻辑运算符的组合
WHERE是整张地图里分支最多的区域。比较运算符有>、>=、<、<=、=、<>和!=,其中<>和!=都表示不等于,前者更标准。逻辑运算符AND、OR、NOT用来拼接条件,AND要求两边都真,OR只要一边真,NOT取反。
-- AND:两个条件同时满足 SELECT * FROM customers WHERE birthdate > '1990-01-01' AND points > 1000; -- OR:满足其一即可 SELECT * FROM customers WHERE birthdate > '1990-01-01' OR points > 1000; -- NOT:对整个条件取反,括号不能省 SELECT * FROM customers WHERE NOT (birthdate > '1990-01-01');NOT后面一定要加括号把整个条件包住,否则取反的只是紧挨着的那一部分,语义完全变样。这是逻辑运算符里最容易写错的地方,也是很多查询结果「看起来对、其实错」的根源。
3.2 IN 与 BETWEEN:列表匹配和区间匹配
IN用来判断某列的值是否落在给定列表里,等价于一串OR,但更短更易读。BETWEEN判断值是否落在闭区间内,两端都包含。
-- 州是 VA、NY、CA 之一 SELECT * FROM customers WHERE state IN ('VA', 'NY', 'CA'); -- 积分在 100 到 200 之间,含两端 SELECT * FROM customers WHERE points BETWEEN 100 AND 200;BETWEEN的边界包含性要记死:BETWEEN 100 AND 200包含 100 和 200。如果业务上要开区间,就得写成> 100 AND < 200。另外BETWEEN用在日期上时,结束日期如果带时间部分,容易漏掉当天末尾的数据,这是实际项目里反复出现的坑。
3.3 LIKE 与 REGEXP:两种模式匹配的分工
LIKE是最简单的模式匹配,只有两个通配符:%匹配任意数量字符,_匹配恰好一个字符。REGEXP走正则,表达能力强得多,笔记里给了锚点、或、字符集三类用法。
-- 名字以 b 开头 SELECT * FROM customers WHERE first_name LIKE 'b%'; -- 以 a 开头 SELECT * FROM customers WHERE first_name REGEXP '^a'; -- 以 ey 或 on 结尾 SELECT * FROM customers WHERE first_name REGEXP 'ey$|on$'; -- 以 my 开头,或包含 se SELECT * FROM customers WHERE first_name REGEXP '^my|se'; -- 包含 b,且 b 后面跟 r 或 u SELECT * FROM customers WHERE first_name REGEXP 'b[ru]';正则里的^是串首、$是串尾、|是逻辑或、[abc]匹配其中任一单字符、[a-d]匹配区间内任一字符。这里最容易混的是LIKE和REGEXP的边界:LIKE 'b%'只匹配开头,REGEXP 'b'只要串里出现 b 就命中,不加锚点就没有位置约束。复习时把「LIKE 默认整串匹配、REGEXP 默认子串搜索」当成一条对照记,能省掉大量调试时间。
3.4 IS NULL:空值不能用等号判断
空值在 SQL 里是「未知」,不是「零」也不是「空字符串」,所以= NULL永远不成立,必须用IS NULL或IS NOT NULL。
-- 没有电话号码的客户 SELECT * FROM customers WHERE phone IS NULL;这条规则单独拎出来说,是因为它是 SQL 三值逻辑的入口。一旦你理解了「NULL 参与比较的结果是未知而不是假」,后面NOT IN遇到 NULL 时的诡异行为也就有了解释的线索。
4. 多表与集合:JOIN 家族和 UNION 的适用边界
4.1 INNER JOIN 与 OUTER JOIN 的取舍
单表查询解决不了关联数据,JOIN就是把两张表按某个键拼起来。INNER JOIN只保留两边都匹配上的行,LEFT JOIN保留左表全部行、右表没匹配上的补空。
-- 内连接:只保留有订单的客户 SELECT * FROM customers c JOIN orders o ON c.customer_id = o.customer_id; -- 左外连接:所有客户都保留,没订单的订单列为空 SELECT * FROM customers c LEFT JOIN orders o ON c.customer_id = o.customer_id;表别名c、o是为了让ON条件写起来短,别名一旦定义,整条语句里就得统一用别名,混用全表名和别名会报错。选INNER还是LEFT取决于业务问题:问「哪些客户下过单」用内连接,问「哪些客户没下过单」就得用左连接再筛右表为空,直接内连接会把没下单的客户整行丢掉,这是需求理解上的错,不是语法错。
4.2 USING 子句与 CROSS JOIN 的两种用途
当两张表的关联列名完全相同时,ON可以简化成USING,写起来更干净。
-- 列名相同,用 USING 简化 SELECT * FROM customers c JOIN orders o USING (customer_id); -- 交叉连接:颜色和尺码两两组合 SELECT * FROM colors CROSS JOIN sizes;USING的前提是列名一模一样,列名不同就只能老老实实写ON。CROSS JOIN生成的是笛卡尔积,行数是两表行数相乘,笔记里用「每种颜色配每种尺码」举例,这是它的正当用途;但如果误把两张没有关联条件的大表写成交叉连接,结果集会爆炸式增长,属于性能上的血泪经验。
4.3 UNION 合并结果集的前提条件
UNION把两个查询的结果纵向拼起来,前提是列数相同、对应列的类型兼容。
-- 合并客户和委托人的姓名地址 SELECT name, address FROM customers UNION SELECT name, address FROM clients;UNION默认去重,要保留重复得写UNION ALL。列名以第一个查询为准,第二个查询的列名会被忽略。合并前先确认两边的列顺序和类型对得上,顺序错了不会报错,只会把地址塞进姓名列,这种错误在结果集里一眼能看出来,但在长语句里很容易漏看。
5. 写入与易错点:INSERT 的写法与五个高频翻车现场
5.1 INSERT 单条与多条插入
写入数据用INSERT INTO ... VALUES,列名列表和值列表要一一对应,不想给值的列可以写DEFAULT让数据库取默认值。
-- 单条插入,phone 显式给 NULL,points 取默认值 INSERT INTO customers(first_name, phone, points) VALUES ('Mosh', NULL, DEFAULT); -- 多条插入,逗号分隔每组值 INSERT INTO customers(first_name, phone, points) VALUES ('Mosh', NULL, DEFAULT), ('Bob', '1234', 10);列名列表建议永远显式写出来,不写列名虽然语法允许,但一旦表结构加了新列,值的顺序就对不上,插入会静默错位。多条插入比逐条插入效率高,因为只走一次语句解析。
5.2 易错点:五个最容易漏的细节
易漏点一:NOT没加括号。漏的原因是NOT优先级高于比较运算符,直觉上以为它作用于整个条件。补法是养成「NOT后面必带括号」的肌肉记忆,写完回读一遍取反范围。
易漏点二:= NULL当空值判断。漏的原因是其他语言里等号能判空,SQL 里 NULL 是未知值。补法是看到空值判断条件先扫一眼有没有IS,没有就改。
易漏点三:LEFT JOIN之后在WHERE里筛右表列。漏的原因是没意识到WHERE在连接之后执行,对右表列加非空条件会把补空的行全部滤掉,左连接退化成内连接。补法是把右表列的过滤条件挪到ON里,或者用IS NULL明确表达「找没匹配上的」。
易漏点四:BETWEEN用在日期上漏掉边界。漏的原因是结束日期带时间部分时,BETWEEN只到当天零点。补法是结束条件改用< 次日,或者把时间部分截断。
易漏点五:LIMIT两个参数写反。漏的原因是偏移和条数的位置不直观。补法是记「先跳后取」,或者统一写成LIMIT n OFFSET m的形式,可读性更好。
6. 复习清单:把三小时笔记压成一张可执行的查漏表
复习这份笔记,不建议从头到尾重读,而是按「能不能默写出来」来筛。下面这张表按模块列出必会项和自检方式,对着过一遍,卡住的那一格就是你要补的地方。
| 模块 | 必会项 | 自检方式 |
|---|---|---|
| 基础骨架 | 语句书写顺序、分号、USE | 不看笔记默写一条带过滤排序截断的查询 |
| 表达式 | 运算优先级、AS别名 | 写出一个带别名的表达式列并解释列头来源 |
| 去重 | DISTINCT作用于整行 | 说出DISTINCT a和DISTINCT a, b的区别 |
| 过滤 | 比较运算符、AND/OR/NOT | 手写一条含NOT加括号的条件 |
| 匹配 | IN、BETWEEN、LIKE、REGEXP | 各写一条,并说明边界包含性 |
| 空值 | IS NULL | 解释为什么= NULL不成立 |
| 连接 | INNER、LEFT、USING、CROSS | 说出左连接退化成内连接的触发条件 |
| 集合 | UNION与UNION ALL | 说明合并时列名以哪边为准 |
| 写入 | 单条与多条INSERT | 写出带DEFAULT的多条插入 |
过完表之后,挑一个自己最不熟的模块做「反向练习」:给一个业务问题,先判断该用哪种连接、哪种匹配方式,再落笔写语句。比如「找出没有下过单的客户姓名」对应左连接加IS NULL,「找出名字以 a 开头或以 n 结尾的客户」对应REGEXP '^a|n$'。这种从问题倒推语法的练法,比顺着笔记抄一遍更能暴露盲区。
我自己的习惯是每次复习前先合上笔记,把第 2 章到第 5 章的骨架语句各默写一条,写不出来的直接标记,只补标记的那几块,不平均用力。三小时课程的内容量不大,真正的难点不在语法本身,而在NULL的三值逻辑、LEFT JOIN的过滤位置、DISTINCT的作用单位这几个反直觉的点上。把这几处吃透,剩下的都是查手册能解决的细节。希望这份梳理能帮到你,也建议把原始笔记和这份清单对照着用,一边默写一边补漏,比单纯重看一遍效率高得多。
本文还有配套的精品资源,点击获取