🙏 我们需要您的帮助!SQLtest.online 没有广告,完全依靠捐款运行。哪怕一点点也很有帮助。 立即捐助 →
SQL 代码已复制到剪贴板

在 WHERE 中组合多个条件

第 2.3 课 · 阅读时间:约 7 分钟 · 练习题 ↓

本课介绍如何在 WHERE 子句中使用逻辑运算符 AND、OR 和 NOT 组合多个条件。你将学会把多个表达式连接起来,构建更精细的过滤条件,准确取出需要的数据子集。我们还会讲解运算符优先级,以及为什么要用括号控制求值顺序、保证查询结果正确。

在 SQL 中组合多个筛选条件

在上一课中,我们学习了如何在 WHERE 子句中使用简单的比较运算符。然而,实际的数据分析经常需要同时按多个条件过滤。为此我们使用逻辑运算符:AND、OR 和 NOT。

SQL 逻辑运算符 AND、OR 和 NOT:AND 先于 OR 计算,因此 (rating = 'G' OR rating = 'PG') AND length < 60 返回 43 部电影,而不加括号的同一条件返回 200 部

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 会按照特定的运算顺序(优先级)求值。

  1. 首先计算 NOT。
  2. 其次计算 AND。
  3. XOR(如果你的 SQL 方言支持)通常在 AND 之后计算。
  4. 最后计算 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 时一定要加括号 (),以避免逻辑错误并提高清晰度。

尝试解决以下任务,以巩固您在本课中学到的内容。

理论题

  1. 逻辑运算符的执行顺序

MySQL

  1. 姓氏以 "A" 开头的客户
  2. 查找以字母 "A" 开头的客户 (2)
  3. 受限影片列表

PostgreSQL

  1. 从多莫杰多沃出发的航班
  2. 按日期获取预订
  3. 获取表列表

SQLite

  1. 按模式搜索
  2. 重型企鹅
  3. 中等大小的企鹅喙

Firebird

  1. 获取员工薪资
  2. 查找非美元/欧元国家

MariaDB

  1. 出版物查询

SQL Server

  1. 按电话区号查询客户