码上问学问代码之理,学编程之道

第 3 章 · 条件、运算符与模糊查询

上一章的 WHERE dynasty = '唐' 只是「一个条件」的入门版。真实需求从来没这么简单——用户要的是「唐宋两朝里、浏览量 200 到 400 之间、标题里带『月』的」。这一章把 WHERE 武装到底:多条件组合、模糊匹配、区间判断、集合判断、空值判断,以及一个几乎人人踩过的坑——别名为什么不能在 WHERE 里用。

多条件组合:AND / OR / NOT

先学会「和、或、非」
多条件组合:把 WHERE 想成一棵「判断树」WHERE 条件AND:都要满足OR:满足其一NOT:取反AND(且)dynasty='唐' AND views>100既要唐朝、又要热门两个条件同时为真才留下OR(或)dynasty='唐' OR dynasty='宋'唐或宋,沾边就要⚠ AND 优先级高于 ORNOT(非)NOT (dynasty='唐')除了唐,其他都要常配合括号使用易错点:AND 比 OR 优先级高,混用必须加括号WHERE dynasty='唐' OR dynasty='宋' AND views>100会被解析为:唐,或(宋且热门)——多半不是你想要的意思规范:每个 OR 组都套上括号,一眼看懂
先讲为什么用户在「古典文学网」列表页上的每一次筛选,本质都是好几个条件的组合:「唐诗」是条件一,勾选「浏览量大于 250」是条件二,两个都要满足。一个 WHERE 只写一个条件,永远不够用。
好消息是这三个连接词和日常语言完全对应:AND 是「并且」(都要满足)、OR 是「或者」(满足一个就行)、NOT 是「不是」(取反)。
动手做(1)AND:两个条件都要满足「唐朝的、而且浏览量超过 250 的」。
AND.sqlsql可运行
SELECT title, dynasty, views
FROM article
WHERE dynasty = '唐' AND views > 250;
查询结果SQL 执行结果
运行结果: title | dynasty | views 静夜思 | 唐 | 328 春望 | 唐 | 256 -- 共 2 行 -- 陋室铭也是唐朝(203),但浏览量没过 250,被 AND 挡掉了
动手做(2)OR:满足其中一个就行「唐朝的,或者浏览量超过 400 的」。注意结果会变多。
OR.sqlsql可运行
SELECT title, dynasty, views
FROM article
WHERE dynasty = '唐' OR views > 400;
查询结果SQL 执行结果
运行结果: title | dynasty | views 静夜思 | 唐 | 328 春望 | 唐 | 256 念奴娇·赤壁怀古 | 宋 | 412 陋室铭 | 唐 | 203 -- 共 4 行 -- 念奴娇是宋朝,本来不符合朝代条件,但浏览量 412 让 OR 放它进来了
动手做(3)NOT:把条件取反「不是唐朝的」。写 NOT dynasty = '唐' 或者更常见的 dynasty != '唐' 都行。
NOT.sqlsql可运行
SELECT id, title, dynasty
FROM article
WHERE NOT dynasty = '唐';
查询结果SQL 执行结果
运行结果: id | title | dynasty 3 | 念奴娇·赤壁怀古 | 宋 4 | 声声慢 | 宋 5 | 天净沙·秋思 | 元 -- 共 3 行
动手做(4)混合使用时,AND 的优先级比 OR 高需求是「宋或唐的作品,且必须是首页推荐的」。下面第一句忘了加括号,结果多出了一条不该有的数据。
优先级-错误.sqlsql可运行
-- 想表达:(宋 或 唐) 且 推荐
-- 实际含义:宋 或 (唐 且 推荐)   ← AND 先算,OR 后算
SELECT title, dynasty, is_recommend
FROM article
WHERE dynasty = '宋' OR dynasty = '唐' AND is_recommend = 1;
查询结果SQL 执行结果
运行结果: title | dynasty | is_recommend 静夜思 | 唐 | 1 春望 | 唐 | 1 念奴娇·赤壁怀古 | 宋 | 1 声声慢 | 宋 | 0 -- 共 4 行 -- 声声慢不是推荐作品(is_recommend = 0),却因为是「宋」被 OR 放进来了
优先级-正确.sqlsql可运行
-- 加上括号,明确告诉数据库先算哪一半
SELECT title, dynasty, is_recommend
FROM article
WHERE (dynasty = '宋' OR dynasty = '唐') AND is_recommend = 1;
查询结果SQL 执行结果
运行结果: title | dynasty | is_recommend 静夜思 | 唐 | 1 春望 | 唐 | 1 念奴娇·赤壁怀古 | 宋 | 1 -- 共 3 行
讲透
  • 优先级:NOT > AND > OR(和数学里「先乘除后加减」一个道理)。所以只要一句话里 AND 和 OR 混着出现,括号就别省:加括号不花钱,漏括号查错数据要命。
  • 三个叫法:AND 叫「逻辑与」,OR 叫「逻辑或」,NOT 叫「逻辑非」。它们操作的对象叫「布尔表达式」——结果只有真、假两种(在 MySQL 里就是 1 和 0)。
  • NOT dynasty = '唐' 和 dynasty <> '唐' 结果一样,但后者更常用也更直观。真正必须用 NOT 的场合,是搭配下面要学的 LIKE / IN / BETWEEN,比如 NOT IN (...)。
  • 落到项目里:作品列表页那排筛选条件(朝代、分类、是否推荐、浏览量区间)拼出来的就是这样一个多条件 WHERE。后端做「动态拼 SQL」时,最容易出错的地方就是括号——第 10 章讲 SQL 注入时还会再碰它。
避坑条件一多,最容易写出「看起来对、其实漏了一条」的语句。养成一个动作:写完 WHERE,先用 SELECT COUNT(*) 数一下命中几行,再用 SELECT * 看具体内容,对着预期数据核对一遍。上面那个「4 行 vs 3 行」的例子,就是靠数行数发现的。

LIKE 与通配符:搜索框的原理

% 和 _ 到底怎么用
LIKE 通配符:% 代表任意长字符,_ 代表一个字符写法含义能查到李%以「李」开头,后面随便李白 · 李商隐%思%中间有「思」就匹配静夜思 · 相思%白以「白」结尾李白_白两个字符,第二个是白李白性能提醒:LIKE '%xx%' 前置 % 无法走索引,大表会全表扫描搜索框场景数据量小没问题;核心大表用全文索引或搜索引擎_ 精确占一位,% 管够——记住这一句就够用
先讲为什么网站顶部那个搜索框,用户输「思」一个字就得找出「静夜思」「天净沙·秋思」;输「念」就得找出「念奴娇·赤壁怀古」。他输的不是完整标题,你要按「包含关系」去找。
判断相等(=)干不了这活,能干这活的是 LIKE + 通配符。这就是搜索框背后最朴素的那句 SQL。
动手做(1)% 代表「任意个字符」前后都加 %,就是「包含」;只加在后面,就是「以某某开头」。
包含匹配.sqlsql可运行
-- 标题里只要出现「思」就算命中
SELECT id, title, author FROM article WHERE title LIKE '%思%';
查询结果SQL 执行结果
运行结果: id | title | author 1 | 静夜思 | 李白 5 | 天净沙·秋思 | 马致远 -- 共 2 行
前缀匹配.sqlsql可运行
-- 以「念」开头(右边不加 % 就是「到此结束」)
SELECT id, title FROM article WHERE title LIKE '念%';
查询结果SQL 执行结果
运行结果: id | title 3 | 念奴娇·赤壁怀古 -- 共 1 行
讲透:两个通配符各管什么
  • % = 0 个、1 个或多个任意字符。'%思%' 包含、'思%' 以「思」开头、'%思' 以「思」结尾。
  • _ = 恰好 1 个任意字符。写几个下划线就代表几个字符,多一个少一个都匹配不上。下面这句用「声声 + 任意 1 个字」去找。
  • 大小写:MySQL 默认的排序规则(utf8mb4_general_ci)不区分大小写,所以 LIKE '%a%' 和 LIKE '%A%' 一个效果。
下划线通配符.sqlsql可运行
-- 「声声」后面恰好还有 1 个字
SELECT id, title FROM article WHERE title LIKE '声声_';

-- 「静」和「思」中间恰好夹 1 个字
SELECT id, title FROM article WHERE title LIKE '静_思';
查询结果SQL 执行结果
运行结果: id | title 4 | 声声慢 -- 共 1 行 id | title 1 | 静夜思 -- 共 1 行
动手做(2)真实搜索框不止查一列用户搜「月」,标题里没有,但正文摘要里有——所以站内搜索通常要把几个字段一起匹配,用 OR 串起来。
站内搜索.sqlsql可运行
-- 标题或摘要里命中「月」
SELECT id, title, summary
FROM article
WHERE title LIKE '%月%' OR summary LIKE '%月%';
查询结果SQL 执行结果
运行结果: id | title | summary 1 | 静夜思 | 床前明月光,疑是地上霜。举头望明月,低头思故乡。 -- 共 1 行 -- 只查 title LIKE '%月%' 的话是 0 行:这个库里没有哪篇作品的「标题」带「月」字 -- 「床前明月光」出现在静夜思的 summary(摘要)里,所以要把摘要一起匹配进来
避坑① 以 % 开头的 LIKE 用不上索引。数据库的索引是按「从头开始」排的,'%思%' 这种前面带通配符的写法只能一行行扫全表。所以「关键词搜索」在高并发站点上往往会换成全文索引(我们库里 article 表就建了一个 ft_article_title_summary)或者独立的搜索引擎。② 别把 % 和 _ 混着数:'声声_' 能匹配 3 个字的「声声慢」,但 '声声%' 能匹配任意长度,做题时看清楚题干要的是「恰好」还是「任意」。

IN:在几个值里挑一个

不用再写一串 OR
先讲为什么前端「朝代」筛选是多选:用户勾了「唐」「宋」两朝。你可以写 dynasty = '唐' OR dynasty = '宋'——能跑,但如果他勾了 8 个朝代呢?你会写到手酸。
IN 就是为这种「在一个集合里挑」而生的语法糖:把候选值放进括号,一句话搞定。
动手做查唐宋两朝的作品;再用 NOT IN 查「除唐宋以外」的。
IN.sqlsql可运行
SELECT id, title, dynasty
FROM article
WHERE dynasty IN ('唐', '宋');
查询结果SQL 执行结果
运行结果: id | title | dynasty 1 | 静夜思 | 唐 2 | 春望 | 唐 3 | 念奴娇·赤壁怀古 | 宋 4 | 声声慢 | 宋 6 | 陋室铭 | 唐 -- 共 5 行
NOT-IN.sqlsql可运行
SELECT id, title, dynasty
FROM article
WHERE dynasty NOT IN ('唐', '宋');
查询结果SQL 执行结果
运行结果: id | title | dynasty 5 | 天净沙·秋思 | 元 -- 共 1 行
讲透
  • IN (a, b, c) 完全等价于 = a OR = b OR = c,NOT IN 则等价于一串 AND。写法更短,读起来也更清楚——「属于这个集合」比「等于 a 或者等于 b 或者等于 c」更贴近人话。
  • 括号里的值可以是各种类型:字符串加单引号,数字不加。混着写也行,如 WHERE id IN (1, 3, 5)。
  • IN 后面还能接一条子查询:WHERE category_id IN (SELECT id FROM category WHERE status = 1)。这是第 5 章的内容,但你现在就该知道「括号里可以不是一个手写清单,而是一段查询」。
  • 落到项目里:多选筛选(朝代、分类、标签)在后端拼参数时,几乎都会拼成 IN (?, ?, ?) 的形式——注意是占位符,不是把用户输入直接塞进去,这是第 10 章 SQL 注入的防线。
避坑NOT IN 有个著名的暗坑:只要括号里出现 NULL,整条语句就会一行都查不出来。因为「不等于未知值」的结果仍然是「未知」,而不是真。所以 dynasty NOT IN ('唐', '宋', NULL) 会返回空结果。写 NOT IN 时,务必确认括号里的清单不含 NULL(老手往往干脆改成 NOT EXISTS)。

BETWEEN … AND …:区间判断

别再写两个条件了
先讲为什么运培后台最常见的需求是「浏览量 200 到 400 的作品」这类区间统计。当然可以写 views >= 200 AND views <= 400,但你要把列名写两遍,很容易一边写错。
BETWEEN … AND … 把这件事收成一句话,可读性也好得多。
动手做筛出浏览量在 200~400 之间的作品,顺便按浏览量倒序,看看区间里的「热门」是谁。
BETWEEN.sqlsql可运行
SELECT title, views
FROM article
WHERE views BETWEEN 200 AND 400
ORDER BY views DESC;
查询结果SQL 执行结果
运行结果: title | views 静夜思 | 328 声声慢 | 298 春望 | 256 陋室铭 | 203 -- 共 4 行 -- 187 的天净沙·秋思低于下限,412 的念奴娇·赤壁怀古高于上限,都被排除了
讲透
  • BETWEEN 是「闭区间」:BETWEEN 200 AND 400 包含 200 和 400 本身,等价于 >= 200 AND <= 400。这一点和数学里的「[200, 400]」一样。
  • 前面加 NOT 就是取反:views NOT BETWEEN 200 AND 400 得到 187 和 412 两条。
  • 字符串和日期也能用,按「字典序」比较。WHERE created_at BETWEEN '2026-01-01' AND '2026-06-30 23:59:59' 就是半年的数据。日期这里要留个心眼:只写 '2026-06-30' 相当于当天的 00:00:00,会把 6 月 30 日白天的数据漏掉。
  • 落到项目里:后台的「数据看板」几乎都是这么算的——选个时间段,然后用 BETWEEN 去统计这段时间的浏览量、新增用户数。
避坑BETWEEN 的两个值必须「小的在前、大的在后」。写成 views BETWEEN 400 AND 200 不会报错,但结果永远是 0 行——因为 MySQL 在找「既大于等于 400、又小于等于 200」的数据,逻辑上不存在。查不出数据时,先低头看看这两个数是不是写反了。

比较运算符与算术运算符

还能在查询里直接算
先讲为什么到这儿你只用过 =。但排行榜要「浏览量大于 300」、库存告警要「小于 5」、筛选要「不小于 200」——这些都是比较运算。
更妙的是,SQL 里还能直接做算术运算:不用把数据取到 Python 里再算,数据库自己就会算好给你。少一次数据搬运,就少一次出错的机会。
动手做(1)比较运算符=、<>(等价于 !=)、>、<、>=、<=,六个够用一辈子。下面这句把两种用法合在一起。
比较运算符.sqlsql可运行
-- <> 和 != 完全等价,推荐写 <>(SQL 标准写法)
SELECT title, views
FROM article
WHERE views <> 328 AND views >= 200
ORDER BY views DESC;
查询结果SQL 执行结果
运行结果: title | views 念奴娇·赤壁怀古 | 412 声声慢 | 298 春望 | 256 陋室铭 | 203 -- 共 4 行 -- 静夜思(328)被 <> 排掉,天净沙·秋思(187)没够 200,也被排掉
动手做(2)算术运算符+ - * / % 都能直接写在 SELECT 里,算出来的列用 AS 起个名字。
算术运算符.sqlsql可运行
SELECT title, views,
       views + 100 AS 加权浏览量,
       views - 100 AS 修正浏览量,
       views % 100 AS 尾数
FROM article
WHERE id <= 3;
查询结果SQL 执行结果
运行结果: title | views | 加权浏览量 | 修正浏览量 | 尾数 静夜思 | 328 | 428 | 228 | 28 春望 | 256 | 356 | 156 | 56 念奴娇·赤壁怀古 | 412 | 512 | 312 | 12 -- 共 3 行 -- % 是取余数:328 % 100 = 28
动手做(3)让数据库顺手算个「点赞率」这类派生指标在后台报表里到处都是:不用改表结构,查的时候算出来就行。
点赞率.sqlsql可运行
-- 先乘 100 再除,避免小数精度损失;ROUND 保留 2 位小数
SELECT title, likes, views,
       ROUND(likes * 100 / views, 2) AS 点赞率百分比
FROM article;
查询结果SQL 执行结果
运行结果: title | likes | views | 点赞率百分比 静夜思 | 42 | 328 | 12.80 春望 | 31 | 256 | 12.11 念奴娇·赤壁怀古 | 58 | 412 | 14.08 声声慢 | 47 | 298 | 15.77 天净沙·秋思 | 22 | 187 | 11.76 陋室铭 | 26 | 203 | 12.81 -- 共 6 行
讲透
  • 比较运算符的「返回什么」:它们的运算结果是布尔值,MySQL 里用 1 表示真、0 表示假。所以你甚至可以写 SELECT views > 300 FROM article,会得到一列 1/0。
  • % 以外还有 MOD(),views % 100 和 MOD(views, 100) 一样;整数相除取整用 DIV(328 DIV 100 得 3)。
  • 除法的坑:MySQL 里整数相除得到的是小数(42 / 328 = 0.1280),不是像 Python 2 那样丢掉小数。但要小心 除数为 0:likes / 0 的结果是 NULL,不会报错,而是悄悄给你一个空值——统计报表里出现空白格子,常常就是这个原因。
  • 凭什么「先乘后除」:likes * 100 / views 先把整数放大,再做除法,得到的精度比 likes / views * 100 更稳。这是数值计算的通用习惯,记一下没坏处。
  • 落到项目里:热度分(浏览量 + 点赞数 × 权重)、完成率、百分比进度条,都是这么在 SQL 里直接算出来的。让数据库算,比取出来让 Python 算更快,代码也更短。
避坑算术表达式如果没有用 AS 起别名,结果列名会长成这样:views + 100,前端拿去用很容易出问题,人看着也别扭。凡是算出来的列,一律 AS 一个名字。另外注意:给整数列做 views - 100 时,如果结果是负数,而该列类型是 int unsigned(无符号),MySQL 会报 BIGINT UNSIGNED value is out of range——这就是为什么「减」要小心,而我们的示例特意先 WHERE id <= 3 保证不会算出负数。

空值判断:IS NULL

空值不是 0,也不是空字符串
先讲为什么不是每条数据都填得满。article 表里 author 可以不填,comment 表里 parent_id 只有「回复别人的评论」才有值——顶层书评它就是空的。
数据库给这种「没有值」用了一个专门的记号:NULL。而 NULL 是最反直觉的东西:它不等于任何值,连它自己都不等于自己。所以判断它不能用 =,只能用 IS NULL。
动手做看看「书评」表里的顶层评论——它们的 parent_id 都是空的。顺便说明一下:article 表的种子数据每一列都有值,所以那里演示不出 NULL,用 comment 表最直观。
IS-NULL.sqlsql可运行
-- 顶层书评(没有父评论)
SELECT id, article_id, parent_id, content
FROM comment
WHERE parent_id IS NULL;
查询结果SQL 执行结果
运行结果: id | article_id | parent_id | content 1 | 1 | NULL | 短短二十字,写尽思乡之情。 2 | 1 | NULL | 小时候背,只觉得朗朗上口;长大后读,才懂那份乡愁。 3 | 3 | NULL | 大江东去,三个字就起势了,果然是豪放派。 -- 共 3 行
IS-NOT-NULL.sqlsql可运行
-- 回复别人的评论(楼中楼)
SELECT id, article_id, parent_id, content
FROM comment
WHERE parent_id IS NOT NULL;
查询结果SQL 执行结果
运行结果: id | article_id | parent_id | content -- 共 0 行 -- 种子数据里 3 条书评都是顶层评论,还没有一条「回复」 -- 要造一条:INSERT INTO comment (user_id, article_id, parent_id, content) VALUES (2, 1, 1, '附议!');
讲透
  • NULL 表示「未知 / 没有」,不是 0,也不是空字符串 ''。「这本书的销量是 0」和「这本书的销量还没统计」是两码事,前者写 0,后者写 NULL。
  • 任何值和 NULL 做比较,结果都是「未知」,而不是真或假。所以 WHERE parent_id = NULL 一行也查不出来,WHERE parent_id <> NULL 同样查不出来。判空只有一个正确写法:IS NULL;判非空:IS NOT NULL。
  • 怎么知道一列能不能为空?回头用 DESC 表名; 看 Null 那一列,写着 YES 就允许存 NULL。
  • 落到项目里:书评的「楼中楼」就是靠 parent_id 这个可空列实现的——顶层评论 parent_id 为 NULL,回复则填上父评论的 id。前端要区分「这是一条评论」还是「这是一条回复」,判断的正是它是不是 NULL。
避坑空字符串 '' 和 NULL 是两回事,判断方式也不一样。看我们的 user 表:avatar 列的默认值是 ''(空字符串),所以「没上传头像」的用户查出来是 '' 而不是 NULL,得用 WHERE avatar = '' 去找;intro 列的默认值是 NULL,就得用 WHERE intro IS NULL。把这两个条件写反,一条数据都查不到——这是新手在「查未填写资料的用户」时最常翻的车。

别名能不能用在条件里

WHERE 不行,ORDER BY 行
先讲为什么上一章你用 AS 给列起了中文别名,用着很顺手,于是很自然地想:既然结果里都叫「浏览量」了,那筛选的时候也写「浏览量」呗?
结果 WHERE 浏览量 > 300 直接报错。原因不神秘——数据库执行语句有固定顺序,WHERE 跑的时候,SELECT 那一行还没执行,别名压根还不存在。想通这一点,这个坑就再也不会踩了。
动手做(1)先看看报错长什么样记住这个错误信息,将来一秒就能反应过来。
WHERE-用别名-报错.sqlsql可运行
-- 错误写法:WHERE 在 SELECT 之前执行,此刻「双倍浏览量」这个别名还不存在
SELECT title, views * 2 AS 双倍浏览量
FROM article
WHERE 双倍浏览量 > 600;
查询结果SQL 执行结果
运行结果: ERROR 1054 (42S22): Unknown column '双倍浏览量' in 'where clause' -- 报错说的是「where 子句里没有这个列」,不是别名拼错了
动手做(2)正确写法:在 WHERE 里把表达式重写一遍
WHERE-正确写法.sqlsql可运行
SELECT title, views * 2 AS 双倍浏览量
FROM article
WHERE views * 2 > 600;
查询结果SQL 执行结果
运行结果: title | 双倍浏览量 静夜思 | 656 念奴娇·赤壁怀古 | 824 -- 共 2 行 -- 等价于 views > 300:328 与 412 过关,298 × 2 = 596 差一点点,被刷掉
动手做(3)但排序时,别名是可以用的因为 ORDER BY 在 SELECT 之后执行,别名这时已经存在了。
ORDER-BY-用别名.sqlsql可运行
SELECT title, views * 2 AS 双倍浏览量
FROM article
ORDER BY 双倍浏览量 DESC
LIMIT 3;
查询结果SQL 执行结果
运行结果: title | 双倍浏览量 念奴娇·赤壁怀古 | 824 静夜思 | 656 声声慢 | 596 -- 共 3 行
讲透:书写顺序 ≠ 执行顺序
  • 你写的时候:SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY → LIMIT。这是语法规定的固定顺序,写反直接报语法错。
  • 数据库执行的时候:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT。看出来了吧,SELECT 排在 WHERE 后面——所以 WHERE 里看不见 SELECT 造的别名,而 ORDER BY 看得见。
  • 哪些地方能用别名:ORDER BY 可以;HAVING 在 MySQL 里也可以(第 4 章会用到);WHERE、GROUP BY 不行,得重写表达式或原始列名。
  • 别把「列别名」和「表别名」搞混:FROM article a 里的 a 是表别名,它在 WHERE 里当然能用(WHERE a.views > 300)——因为 FROM 是第一步,表别名早就定好了。第 5 章的多表连接会天天用到它。
避坑给列起别名时不要和真实列名重名。比如写 SELECT likes * 2 AS likes,读代码的人就再也分不清这个 likes 是原始列还是算出来的东西,稍后如果再写 ORDER BY likes,MySQL 甚至可能按原始列排,结果跟你以为的不一样。别名要起得「看得出是它算出来的」,像 双倍浏览量、点赞率百分比 就很好。
动手练习
1查出标题里含有「思」的作品,显示标题和作者(提示:用 LIKE + 通配符)。
2查出浏览量在 200 到 300 之间的作品,按浏览量从高到低排列。
3迁移练习:「红影赏析」的 movie 表字段是 id、title、genre、rating、director。请查出导演是「诺兰」或「郭帆」、并且评分不低于 8.0 的电影,按评分从高到低排列。写完后想一想:这里为什么用 IN 比写两个 OR 更好,以及为什么这一句里 IN 和 AND 混用却不必加括号。
参考答案
练习答案.sqlsql可运行
-- 第 1 题
SELECT title, author FROM article WHERE title LIKE '%思%';

-- 第 2 题
SELECT title, views
FROM article
WHERE views BETWEEN 200 AND 300
ORDER BY views DESC;

-- 第 3 题(红影赏析的库,表结构不同,思路一致)
SELECT title, director, rating
FROM movie
WHERE director IN ('诺兰', '郭帆') AND rating >= 8.0
ORDER BY rating DESC;
查询结果SQL 执行结果
运行结果: -- 第 1 题 title | author 静夜思 | 李白 天净沙·秋思 | 马致远 -- 共 2 行 -- 第 2 题 title | views 声声慢 | 298 春望 | 256 陋室铭 | 203 -- 共 3 行 -- 下限 200、上限 300 都含在内;天净沙·秋思 187 太低,念奴娇 412 太高 -- 第 3 题(在红影的库里执行) title | director | rating 星际穿越 | 诺兰 | 9.3 流浪地球 | 郭帆 | 8.4 -- 共 2 行 -- 数据以红影库里的为准

第 3 题的关键:IN 相当于把一串「或」压缩成一个条件,读起来就是「导演属于 {诺兰, 郭帆}」。因为压缩之后整句只剩 AND 连接、没有裸露的 OR,所以不加括号也不会算错;但如果写成 director = '诺兰' OR director = '郭帆' AND rating >= 8.0,就必须给「或」的那半加括号,否则 AND 会先算,结果就错了。

本章小结