跳到主要内容

逻辑操作符

逻辑操作符用于把多个条件组合成一个条件。最常见的三个操作符是:

操作符含义直观理解
AND并且所有条件都满足
OR或者至少一个条件满足
NOT非把条件结果反过来

它们最常出现在 WHERE 和 HAVING 中,也可以用于 JOIN ... ON、CASE WHEN 和检查约束(CHECK)。本文以通用 SQL 为主;布尔类型、字符串比较规则和短路执行等细节可能因数据库而异。

AND:同时满足​

SELECT user_id, username
FROM users
WHERE status = 'active'
AND login_count >= 10;

只有 status = 'active' 并且 login_count >= 10 都为真时,行才会被保留。增加一个 AND 条件通常会缩小结果集。

OR:满足其一​

SELECT product_id, product_name, status
FROM products
WHERE status = 'on_sale'
OR stock = 0;

只要有一个条件为真,行就会被保留。OR 很容易因为范围过宽而返回超出预期的数据,复杂条件应使用括号明确分组。

NOT:否定条件​

SELECT order_id, status
FROM orders
WHERE NOT (status = 'cancelled');

NOT 只作用于紧随其后的条件表达式。建议给复合条件加括号,不要依赖读者记忆它的作用范围:

WHERE NOT (status = 'cancelled' OR status = 'refunded')

这表示既不是已取消,也不是已退款。对于单个谓词,也常见等价写法 status <> 'cancelled',但遇到 NULL 时两者都不会匹配 NULL。

优先级与括号​

在没有括号时,常见优先级从高到低是:NOT、AND、OR。因此:

WHERE is_member = TRUE OR is_staff = TRUE AND age >= 18

会被解释为:

WHERE is_member = TRUE
OR (is_staff = TRUE AND age >= 18)

如果业务意图是“会员或员工都必须年满 18 岁”,就必须写成:

WHERE (is_member = TRUE OR is_staff = TRUE)
AND age >= 18

括号不只是为了改变计算顺序,也是给读者和未来维护者的明确说明。混合使用 AND、OR、NOT 时,优先加括号。

真值表:先理解组合规则​

对只有 TRUE 和 FALSE 的简单布尔值,规则如下:

AND​

ABA AND B
TRUETRUETRUE
TRUEFALSEFALSE
FALSETRUEFALSE
FALSEFALSEFALSE

OR​

ABA OR B
TRUETRUETRUE
TRUEFALSETRUE
FALSETRUETRUE
FALSEFALSEFALSE

NOT​

ANOT A
TRUEFALSE
FALSETRUE

实际 SQL 还要考虑 NULL,这时不是二值而是三值逻辑。

NULL 与三值逻辑​

NULL 表示未知或缺失,不等于 FALSE。比较结果可能是 UNKNOWN(未知):

SELECT *
FROM users
WHERE nickname = 'Lee';

nickname 为 NULL 的行,其比较结果是 UNKNOWN,而 WHERE 只保留结果为 TRUE 的行,因此不会返回该行。

涉及 UNKNOWN 时,核心规则如下:

ABA AND BA OR B
TRUEUNKNOWNUNKNOWNTRUE
FALSEUNKNOWNFALSEUNKNOWN
UNKNOWNUNKNOWNUNKNOWNUNKNOWN

NOT UNKNOWN 仍然是 UNKNOWN。所以以下条件都不会把 NULL 当成“不是该值”:

WHERE status <> 'active'
WHERE NOT (status = 'active')

如果要包含空值,必须显式写出:

WHERE status <> 'active' OR status IS NULL

判断空值使用 IS NULL 和 IS NOT NULL,不要写 status = NULL 或 status <> NULL。

与常用谓词组合​

逻辑操作符可以和其他谓词一起使用:

SELECT order_id, total_amount
FROM orders
WHERE status IN ('paid', 'shipped')
AND total_amount BETWEEN 100 AND 1000
AND customer_id IS NOT NULL;

常见谓词包括:

  • IN:匹配集合中的任意值;
  • BETWEEN:匹配闭区间,等价于 value >= low AND value <= high;
  • LIKE:按模式匹配字符串;
  • IS NULL:判断空值;
  • EXISTS:判断子查询是否至少返回一行。

否定集合或范围时,可使用 NOT IN、NOT BETWEEN 和 NOT LIKE。注意 NOT IN 的列表或子查询结果中若含 NULL,整体判断可能变为 UNKNOWN;需要排除这个影响时,应过滤 NULL 或改用 NOT EXISTS。

常见等价改写与陷阱​

德摩根定律​

在不考虑 NULL 的纯二值条件下:

NOT (A AND B) = (NOT A) OR (NOT B)
NOT (A OR B) = (NOT A) AND (NOT B)

例如:

WHERE NOT (status = 'disabled' OR is_deleted = TRUE)

可以改写为:

WHERE status <> 'disabled'
AND is_deleted <> TRUE

但存在 NULL 时,改写后的结果可能不同;若要保留空值语义,请分别补充 IS NULL 判断并用测试验证。

不要把 OR 条件误放到连接外​

SELECT c.customer_id, o.order_id
FROM customers AS c
LEFT JOIN orders AS o
ON o.customer_id = c.customer_id
WHERE o.status = 'paid' OR c.vip_level = 'gold';

这里 WHERE 中对 o.status 的条件会影响左连接结果。若目标是“保留所有客户,并只连接已支付订单”,应将订单条件放入 ON:

LEFT JOIN orders AS o
ON o.customer_id = c.customer_id
AND o.status = 'paid'

用括号避免“条件泄漏”​

-- 只允许已启用用户,并且属于管理员或编辑者
WHERE status = 'active'
AND (role = 'admin' OR role = 'editor')

没有括号时,OR 可能让 status = 'active' 约束只作用于其中一部分条件。

执行与性能注意事项​

逻辑表达式描述的是结果规则,不保证数据库会按书写顺序逐项执行,也不能依赖“短路”来避免错误:

-- 不要假设第一项为 FALSE 时,第二项一定不会计算
WHERE amount <> 0 AND total_amount / amount > 10

需要安全处理除零时,应使用 NULLIF 等明确表达式:

WHERE total_amount / NULLIF(amount, 0) > 10

索引是否生效取决于数据库优化器、数据分布和表达式写法。不要为了“看起来更快”随意改写逻辑;应通过 EXPLAIN 或数据库提供的执行计划工具验证。对可选筛选条件,应用层应使用参数化查询,并明确每个参数为 NULL 时的业务含义。

CASE 与检查约束中的逻辑​

逻辑操作符不限于 WHERE:

SELECT order_id,
CASE
WHEN status = 'paid' AND total_amount >= 1000 THEN '重点订单'
WHEN status = 'paid' THEN '普通已支付订单'
ELSE '其他'
END AS order_level
FROM orders;

也可以在表约束中限制组合状态:

CONSTRAINT ck_delivery_status
CHECK (
status <> 'delivered'
OR delivered_at IS NOT NULL
)

检查约束对 UNKNOWN 的处理和约束是否真正生效,可能随数据库而异;需要强制禁止 NULL 时,应同时声明相关列为 NOT NULL。

编写可靠条件的步骤​

  1. 先用自然语言写清楚“全部满足”还是“满足其一”。
  2. 把每个原子条件单独列出,再用括号组合。
  3. 检查每个可空列:NULL 应该被排除、保留,还是单独处理?
  4. 混合 AND、OR、NOT 时显式写括号。
  5. 用包含边界值、NULL 和不满足条件的样例数据测试。
  6. 对复杂查询查看执行计划,确认逻辑正确且性能可接受。

小结​

  • AND 要求全部条件为真,OR 要求至少一个条件为真,NOT 否定一个条件。
  • 常见优先级是 NOT 高于 AND,AND 高于 OR;复杂表达式应主动加括号。
  • SQL 使用 TRUE、FALSE、UNKNOWN 三值逻辑,NULL 比较通常得到 UNKNOWN。
  • IS NULL、IS NOT NULL 专门判断空值;NOT IN 遇到 NULL 要特别小心。
  • 不要依赖短路执行或隐式优先级;用明确表达式、参数化查询和边界测试保证结果可靠。