WHERE 1=1 是为简化动态SQL条件拼接而设的占位技巧,它本身无功能且被优化器忽略,真正起作用的是后续AND连接的可选条件;必须配合参数化查询防范SQL注入,复杂场景推荐显式构建条件列表。

WHERE 1=1 是一种常见但需谨慎使用的动态拼接技巧,它本身不提供功能,只降低条件拼接的逻辑复杂度;真正起作用的是后续用 AND 连接的可选条件。
为什么用 WHERE 1=1 而不是直接写 WHERE
在程序中拼接 SQL(如 Python、Java 拼接字符串或 MyBatis 的 <if>)时,如果所有查询条件都可能为空,手动判断第一个条件是否该加 WHERE 或 AND 很容易出错。用 WHERE 1=1 后,每个条件统一以 AND column = ? 形式追加,省去首条件分支判断。
- 避免漏写
WHERE导致语法错误(如SELECT * FROM t AND name = 'a') - 避免多条件时重复判断“当前是第几个有效条件”,尤其嵌套 if/else 时易错
- 数据库优化器会直接忽略
1=1,对执行计划和性能无实质影响(MySQL、PostgreSQL、SQL Server 均如此)
实际拼接时必须配合参数化,否则有 SQL 注入风险
WHERE 1=1 本身不危险,但若拼接值时直接插入用户输入,就等于敞开 SQL 注入大门。必须使用预编译参数(?、:name、@p1 等),而不是字符串格式化。
- ✅ 正确:
"WHERE 1=1 AND status = ? AND created_at > ?"+ 绑定参数列表 - ❌ 危险:
"WHERE 1=1 AND name = '" + user_input + "'"—— 单引号闭合后可任意执行 - MyBatis 中应使用
<if test="name != null">AND name = #{name}</if>,而非${name} - JDBC 中必须用
PreparedStatement,不能用Statement拼接
替代方案:更清晰的逻辑控制(推荐用于复杂场景)
当条件分支较多、含 OR 或子查询时,WHERE 1=1 容易让 SQL 变得难读且难以调试。此时建议改用显式构建 where 子句的方式:
- 在代码中维护一个
List<String> conditions和List<Object> params - 每满足一个条件,就
add("status = ?")并add(statusValue) - 最后用
String.join(" AND ", conditions)拼出完整 where 部分,空集合时整个 where 省略 - 比
1=1更易单元测试、日志输出、审计追踪
注意 NULL 值和空字符串的语义处理
很多业务逻辑里,“未填写”不等于“查所有”,而是要排除 NULL 或空值。仅靠 1=1 不解决这个问题,需明确字段的默认行为:
- 若前端传空字符串
""表示“不限”,则条件应跳过该字段,而非生成AND name = '' - 若字段允许 NULL,且想查“未设置”的记录,应写
AND name IS NULL,不能写= NULL - 日期范围常用
AND created_at >= COALESCE(?, '1970-01-01'),但需注意数据库兼容性(PostgreSQL 支持,MySQL 需转类型)
真正麻烦的从来不是 1=1 本身,而是条件逻辑没想清就急着拼 SQL —— 比如把“多个状态用 IN 查询”写成一堆 OR status = ?,或者忽略索引失效场景(函数包裹字段、隐式类型转换)。写之前先画清楚业务规则边界,比选哪种拼接姿势重要得多。

















