在 WHERE 中组合多个条件
第 2.3 课 · 阅读时间:约 7 分钟 · 练习题 ↓
本课介绍如何在 WHERE 子句中使用逻辑运算符 AND、OR 和 NOT 组合多个条件。你将学会把多个表达式连接起来,构建更精细的过滤条件,准确取出需要的数据子集。我们还会讲解运算符优先级,以及为什么要用括号控制求值顺序、保证查询结果正确。
在 SQL 中组合多个筛选条件
在上一课中,我们学习了如何在 WHERE 子句中使用简单的比较运算符。然而,实际的数据分析经常需要同时按多个条件过滤。为此我们使用逻辑运算符:AND、OR 和 NOT。
SQL 中的逻辑运算符
逻辑运算符可以把 WHERE 子句中的多个表达式连接起来,构建更复杂的过滤条件。
AND 运算符
只有当 AND 连接的所有条件都为真时,AND 运算符才返回该行。它用于缩小结果范围。
示例(Sakila 数据库) 假设我们要找出分级为 'G' 并且时长少于 80 分钟的电影:
SELECT title, length, rating
FROM film
WHERE length < 80 AND rating = 'G';
结果:只返回同时满足两个条件的电影。
OR 运算符
只要 OR 连接的条件中任意一个为真,OR 运算符就返回该行。它用于扩大结果范围。
示例(Sakila 数据库) 查找名字为 'NICK' 或 'ED' 的演员:
SELECT first_name, last_name
FROM actor
WHERE first_name = 'NICK' OR first_name = 'ED';
结果:演员名字与其中至少一个值匹配的行。
NOT 运算符
当条件不为真时,NOT 运算符返回该行。在实践中,它常与 IN 和 LIKE 一起使用,用来排除一组值或某种文本模式。
示例 1:排除一个分级
查找除 'R' 级以外的所有电影:
SELECT title, rating
FROM film
WHERE NOT rating = 'R';
结果:分级不是 'R' 的所有电影。
示例 2:用 NOT IN 排除多个值
如果要一次排除多个分级,用 NOT IN 更方便:
SELECT title, rating
FROM film
WHERE rating NOT IN ('R', 'NC-17');
结果:分级不在 'R' 和 'NC-17' 列表中的电影。
示例 3:用 NOT LIKE 对模式取反
如果要排除以字母 A 开头的片名:
SELECT title
FROM film
WHERE title NOT LIKE 'A%';
结果:片名不以 A 开头的电影。
XOR 运算符(异或,很少使用)
只有当两个条件中恰好一个为真时,XOR 运算符才返回真。实践中它很少使用,因为并非所有 SQL 方言都支持它,而且会降低查询的可读性。
示例(Sakila 数据库) 查找只满足一个条件的电影:要么时长少于 60 分钟,要么分级为 'G',但两者不能同时满足:
SELECT title, length, rating
FROM film
WHERE length < 60 XOR rating = 'G';
为了在不同数据库之间通用,同样的逻辑通常用 AND/OR/NOT 来写。
运算符优先级
当你在一条查询中组合多个运算符(例如同时使用 AND 和 OR)时,SQL 会按照特定的运算顺序(优先级)求值。
- 首先计算
NOT。 - 其次计算
AND。 XOR(如果你的 SQL 方言支持)通常在AND之后计算。- 最后计算
OR。
括号的作用:
和数学中一样,应该使用括号 () 来控制求值顺序,并让查询更易读。如果不加括号,SQL 会默默套用默认的优先级,结果可能并不是你想要的。
查找时长少于 60 分钟的 'G' 和 'PG' 级电影
有错误的查询:缺少括号
-- BUG: AND binds tighter than OR, so this is evaluated as:
-- rating = 'G' OR (rating = 'PG' AND length < 60)
-- Result: ALL 'G' films (any length) + only SHORT 'PG' films
SELECT title, length, rating
FROM film
WHERE rating = 'G' OR rating = 'PG' AND length < 60;
错在哪里: AND 条件先被计算,所以 length < 60 过滤只作用于 'PG' 级电影,而所有 'G' 级电影无论时长多少都会被返回。
修正后的查询:用括号明确意图
-- CORRECT: parentheses force OR to be evaluated first
-- Result: only films rated 'G' OR 'PG' AND shorter than 60 minutes
SELECT title, length, rating
FROM film
WHERE (rating = 'G' OR rating = 'PG') AND length < 60;
结果:只返回分级为 'G' 或 'PG' 且时长少于 60 分钟的电影。
同时排除 'R' 级和 'NC-17' 级电影
有错误的查询:NOT 只否定第一个条件
-- BUG: NOT applies only to the immediately following condition
-- Equivalent to: (NOT rating = 'R') AND rating = 'NC-17'
-- Result: films rated 'NC-17' that are also not rated 'R' - always empty
SELECT title, rating, length
FROM film
WHERE NOT rating = 'R' AND rating = 'NC-17';
错在哪里: NOT 只否定了 rating = 'R',而 rating = 'NC-17' 仍然是一个正向过滤条件。实际上,这条查询会返回所有 'NC-17' 级电影:因为 'NC-17' 不是 'R',这些行总是满足 NOT 条件。查询非但没有排除 NC-17 级电影,返回的恰恰是你想排除的那些电影。
方案 A:写两个明确的 NOT 条件
-- CORRECT: each condition is independently negated
SELECT title, rating, length
FROM film
WHERE NOT rating = 'R' AND NOT rating = 'NC-17';
方案 B:NOT 加括号(更简洁)
-- CORRECT: NOT applies to the whole OR group
SELECT title, rating, length
FROM film
WHERE NOT (rating = 'R' OR rating = 'NC-17');
两种方案返回的结果相同。排除多个值时通常更推荐方案 B,因为列表变长时它更容易扩展。
常见问题
什么时候用 AND,什么时候用 OR?
当一行必须同时满足所有条件时,使用 AND。当满足多个条件中的任意一个就够时,使用 OR。如果两个运算符出现在同一条查询中,最好加上括号。
NOT IN 与多个 AND 条件有什么不同?
NOT IN 是从同一列中排除多个值的简洁写法。与一长串用 AND 连接的否定比较相比,它更易读,也更容易扩展。
什么时候使用 NOT LIKE?
当你想排除与某个文本模式匹配的行时,使用 NOT LIKE。它适合按前缀、后缀或子串做反向过滤。
面试问题
面试时你会如何解释 SQL 的运算符优先级?
在 SQL 中,先计算 NOT,再计算 AND,最后计算 OR。当查询混用多个运算符时,括号可以明确表达预期的逻辑,防止出现意外结果。
什么时候用 NOT IN 而不是 NOT =?
当需要从同一列中排除多个值时,使用 NOT IN。与用 AND 重复写多个比较相比,它更易读,也更容易扩展。
NOT LIKE 如何工作?
NOT LIKE 返回与指定模式不匹配的行。例如,title NOT LIKE 'A%' 会排除所有以 A 开头的片名。
为什么括号在复杂的 WHERE 子句中很重要?
括号控制求值顺序,消除 AND 和 OR 之间的歧义。它们让你准确写出想要的逻辑,而不是依赖默认的优先级。
本课要点:
- 用
AND确保所有条件都满足。 - 用
OR查找满足多个条件中任意一个的行。 - 用
NOT、NOT IN和NOT LIKE排除数据。 - 谨慎使用
XOR:它可能有用,但并非所有 SQL 方言都支持。 - 混用
AND和OR时一定要加括号(),以避免逻辑错误并提高清晰度。