首页/数据/SQL 速查/行构造器比较 (a, b) IN ((…),(…))

行构造器比较 (a, b) IN ((…),(…))

把多个列当作一个元组参与 IN 或等值比较,表达“多列组合命中多个候选项”比 OR 链更短更清晰。

SQL 速查数据更新于 2026-10-13

行构造器比较

行构造器把多个列当作一个元组参与比较:WHERE (city, status) IN (('Beijing', 1), ('Shanghai', 2)) 比一串 OR 更短、更不容易写错括号。MySQL 与 PostgreSQL 都支持,(a, b) = (1, 2) 这种等值比较也属于同一族语法。

基本信息

等价改写(a,b) IN ((1,2),(3,4)) 即 (a=1 AND b=2) OR (a=3 AND b=4)
比较规则按从左到右逐列比较
元素个数每行元素个数必须与左侧列数一致
索引影响部分版本下行比较的索引利用弱于展开写法
适用平台MySQL 与 PostgreSQL 均支持

典型使用场景

  • 按「城市加状态」这类多列组合批量筛选
  • 把冗长的 OR 链改写成更易读的形式
  • 按复合主键批量查询
  • 对比改写前后的执行计划差异
  • 用简单元组比较做业务规则的二次校验

示例

示例
-- 多列组合命中:比 OR 链更短
SELECT * FROM t
WHERE (city, status) IN (('Beijing', 1), ('Shanghai', 2));

-- 等值比较
SELECT * FROM t WHERE (a, b) = (1, 2);

-- 与展开写法等价,改写后可用 EXPLAIN 对比
SELECT * FROM t
WHERE (city = 'Beijing' AND status = 1)
   OR (city = 'Shanghai' AND status = 2);

常见用法

写法含义注意
(a, b) = (1, 2)两列分别相等元素个数必须对齐
(a, b) IN ((1,2),(3,4))命中任一组合等价于 AND/OR 展开
(a, b) > (1, 2)逐列字典序比较语义不直观,慎用
(a, b) IS NULL判断整体是否为 NULL与逐列 IS NULL 语义不同
行比较的索引利用不如展开写法稳定:部分版本上优化器无法把它拆成两次索引范围扫描。重要查询改写后用 EXPLAIN 对比,别只看语句更短。
候选组合很多时(上百条)建议改用临时表连接或批量接口:超长 IN 列表既难维护,也会给优化器带来额外负担。
行构造器也能和子查询配合,例如 (a, b) IN (SELECT x, y FROM t),写法简洁但同样要确认列数与类型一致,否则报错信息不太直观。
批量接口里用它传多组键值很常见:此时要注意列表长度,几百组以上时改用临时表连接或分批查询,索引利用与可读性都会更好。

易错点

  • 每行元素个数与左侧列数不一致:直接语法报错,列表长时不容易一眼看出
  • 以为行比较一定能用索引:部分版本索引利用弱于 AND/OR 展开,重要查询要用 EXPLAIN 验证
  • 用 (a,b) > (1,2) 表达业务条件:逐列字典序比较的语义不直观,容易写出与预期不符的范围
  • 用行构造器做 NULL 判断:(a,b) IS NULL 与逐列判断语义不同,可能漏掉部分为 NULL 的行
  • 候选组合几百条还写成 IN 列表:语句长、优化器负担重,改用临时表或批量接口更合适

数据来源与参考

  • MySQL 8.0 Reference Manual · Row Constructor Expressions
  • PostgreSQL Documentation · Row Constructors
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌