乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 数据库基础与安装

    • MySQL 简介
    • MySQL 5.6 到 5.7 到 8.0 关键差异速查
    • 安装 MySQL 5.7
    • 连接与断开服务器
    • 创建数据库
    • 创建数据表
    • 数据库与数据表
    • 加载数据
    • 获取数据库信息
    • 批处理模式
    • SHOW 语句汇总
    • FLUSH 与 RESET 语句
    • my.cnf 核心参数
    • 字符集与排序规则
  • 第2章 SQL基础查询

    • SELECT
    • WHERE
    • ORDER BY
    • LIMIT
    • COUNT
    • 聚合函数
    • 比较运算符
    • 逻辑运算符
    • 算术运算符
    • 模式匹配
    • NULL 值处理
    • UPDATE
    • DELETE
    • REPLACE
    • SELECT INTO
  • 第3章 数据类型与运算符

    • 数值类型
    • 字符串类型
    • 日期时间类型
    • BIT 类型
    • ENUM 类型
    • SET 类型
    • JSON 类型
    • 类型转换
  • 第4章 函数与表达式

    • 字符串函数
    • 数值函数
    • 日期函数
    • 全文检索函数
  • 第5章 高级查询与子查询

    • JOIN
    • 子查询
    • UNION
    • GROUP BY
    • HAVING
    • DISTINCT
  • 第6章 表与索引

    • 数据定义语言
    • 修改表结构
    • 视图
    • 修改视图与检查选项
    • 外键
    • 索引
    • 唯一索引
    • 复合索引
    • 存储引擎对比
    • 分区表
    • 第一范式与第二范式
    • 第三范式与 BC 范式
    • 反范式设计
  • 第7章 存储过程与函数

    • 存储过程
    • 存储函数
    • 变量
    • 流程控制
    • 游标
    • 预处理语句
  • 第8章 事务与锁

    • 事务
    • 事务隔离级别
    • 锁机制
    • MVCC
    • 死锁专题分析
    • LOCK TABLES
    • XA 事务
  • 第9章 用户管理与安全

    • 用户管理
    • 权限管理
    • 角色
    • SQL 注入防范
  • 第10章 性能优化入门

    • 执行计划
    • 索引优化
    • 查询优化
    • 查询优化器提示
    • 慢查询日志
    • InnoDB 深入机制
    • InnoDB 专项优化
    • Performance Schema
    • sys Schema
  • 第11章 复制与高可用

    • 主从复制原理
    • 半同步复制配置
    • binlog 开启与 point-in-time 恢复
    • mysqldump 全库备份
    • mysqldump 单表与条件备份
    • mysqldump 恢复与导入
    • xtrabackup 全量热备
    • xtrabackup 准备与恢复
    • xtrabackup 增量与流式备份
  • 第12章 触发器与事件

    • 触发器
    • 事件调度器
  • 参考

    • MySQL 5.7 专业术语大全
    • MySQL 5.7 关键字与保留字大全

WHERE

导学

一张表可能有百万行数据,但你通常只关心其中满足特定条件的少数行。WHERE 子句就是 SQL 的"筛选器",它决定哪些行会被返回。

定义

WHERE:用于在 SELECT、UPDATE、DELETE 语句中指定过滤条件,只有满足条件的行才会被处理。WHERE 在 SQL 执行顺序中紧跟 FROM 之后。

核心语法

SELECT 列 FROM 表 WHERE 条件;

条件可以是:

  • 比较运算:=, <>, !=, >, <, >=, <=
  • 逻辑运算:AND, OR, NOT
  • 范围判断:BETWEEN ... AND ...
  • 集合判断:IN (...)
  • 模糊匹配:LIKE
  • 空值判断:IS NULL, IS NOT NULL

演示数据准备

DROP TABLE IF EXISTS employees;

CREATE TABLE employees (
    emp_id INT PRIMARY KEY AUTO_INCREMENT,
    emp_name VARCHAR(20),
    dept VARCHAR(20),
    score DECIMAL(5,2)
);

INSERT INTO employees (emp_name, dept, score) VALUES
('大翔', '技术部', 100),
('白歌', '技术部', NULL);

当前 employees 表中的完整数据如下:

emp_idemp_namedeptscore
1大翔技术部100
2白歌技术部NULL

SQL 示例

场景一:精确匹配

当前数据状态:见上文 employees 表完整数据。

执行语句:

SELECT emp_name, dept FROM employees WHERE dept = '技术部';

操作后结果:

emp_namedept
大翔技术部
白歌技术部

结果解读:只返回 dept = '技术部' 的行。字符串比较在 MySQL 中默认不区分大小写(取决于排序规则)。如需区分大小写,可使用 BINARY 关键字:WHERE BINARY dept = '技术部' 仍返回相同结果(因为本身大小写已匹配)。

场景二:范围查询(BETWEEN)

当前数据状态:见上文 employees 表完整数据。

执行语句:

SELECT emp_name, score FROM employees
WHERE score BETWEEN 80 AND 100;

操作后结果:

emp_namescore
大翔100.00

结果解读:BETWEEN 是闭区间,包含两端边界。它等价于 score >= 80 AND score <= 100。共返回 1 行,白歌(score 为 NULL)被排除。

场景三:集合查询(IN)

当前数据状态:见上文 employees 表完整数据。

执行语句:

SELECT emp_name, dept FROM employees
WHERE dept IN ('技术部');

操作后结果:

emp_namedept
大翔技术部
白歌技术部

结果解读:IN 等价于多个 OR 的简写:dept = '技术部'。当前表中只有技术部一个部门。当集合元素较多时,IN 比一长串 OR 更简洁。

场景四:排除查询(不等于)

当前数据状态:见上文 employees 表完整数据。

执行语句:

SELECT emp_name, score FROM employees
WHERE dept <> '技术部';

操作后结果:

emp_namescore

结果解读:<> 表示不等于,排除了大翔和白歌(技术部)。当前表中所有员工都在技术部,因此没有数据返回。

易错点:判断 NULL 不能用 = NULL 或 <> NULL,必须用 IS NULL 或 IS NOT NULL。这是 SQL 标准规定的三值逻辑(真、假、未知)导致的。

场景五:NULL 判断(IS NULL / IS NOT NULL)

当前数据状态:见上文 employees 表完整数据,其中白歌的 score 为 NULL。

执行语句(错误写法):

-- 错误写法(永远返回空结果)
SELECT * FROM employees WHERE score = NULL;

操作后结果:空结果集(0 行)。

结果解读:任何值与 NULL 的比较结果都是 UNKNOWN,而 WHERE 只保留 TRUE 的行,因此没有任何行满足条件。

执行语句(正确写法):

SELECT emp_name, score FROM employees WHERE score IS NULL;

操作后结果:

emp_namescore
白歌NULL

结果解读:IS NULL 是专门判断 NULL 的运算符,正确返回了 score 为 NULL 的白歌。

再看 IS NOT NULL:

SELECT emp_name, score FROM employees WHERE score IS NOT NULL;

操作后结果:

emp_namescore
大翔100.00

结果解读:返回了所有 score 不为 NULL 的 1 行。

场景六:复合条件(AND / OR)

当前数据状态:见上文 employees 表完整数据。

执行语句:

SELECT emp_name, dept, score FROM employees
WHERE dept = '技术部' AND score >= 90;

操作后结果:

emp_namedeptscore
大翔技术部100.00

结果解读:AND 要求两个条件同时满足。技术部部门的员工有大翔、白歌,但白歌的 score 为 NULL(不满足 >= 90),因此只有大翔被返回。

再看一个 OR 的例子:

SELECT emp_name, dept, score FROM employees
WHERE dept = '产品部' OR score IS NULL;

操作后结果:

emp_namedeptscore
白歌技术部NULL

结果解读:OR 要求满足任一条件即可。白歌的 score IS NULL,满足条件,因此被返回。大翔的 dept 为技术部且 score 不为 NULL,不满足任一条件。

WHERE 与索引的关系

WHERE 条件是索引优化的核心入口。如果 WHERE 条件中的列有合适的索引,MySQL 可以直接定位到目标行;否则将进行全表扫描。

关于索引的详细内容,参见第05章《索引》文档。

常见误区

误区正解
WHERE 1=1 无影响虽然结果正确,但会让优化器难以处理,且显得业余。动态 SQL 应去掉多余的 AND。
字符串比较区分大小写MySQL 默认排序规则(如 utf8mb4_unicode_ci)不区分大小写。
WHERE column = NULL任何值与 NULL 的比较结果都是 UNKNOWN,必须用 IS NULL。
WHERE 中可以用 SELECT 别名不行,WHERE 在 SELECT 之前执行,别名还未生成。

面试考点

Q:WHERE 和 HAVING 的区别?

WHERE 在分组前过滤行,不能引用聚合函数;HAVING 在分组后过滤组,可以引用 SUM、COUNT 等聚合函数。执行顺序:WHERE 先于 GROUP BY 和 HAVING。

Q:IN 和 OR 有什么区别?性能上哪个好?

逻辑上等价,但 IN 更简洁。MySQL 5.7 中两者通常会被优化为相同的执行计划。当 IN 列表很长时,性能可能不如 JOIN 子查询。

Q:为什么 WHERE column = NULL 查不到数据?

SQL 使用三值逻辑:TRUE、FALSE、UNKNOWN。任何值与 NULL 的比较结果都是 UNKNOWN,而 WHERE 只保留 TRUE 的行。必须使用 IS NULL。

Q:如何查询"某列不等于某值"且包含 NULL 的行?

WHERE column <> '某值' OR column IS NULL。因为 column <> '某值' 对 NULL 返回 UNKNOWN,不会包含 NULL 行,必须显式加上 OR column IS NULL。

小结

  • WHERE 是行级过滤器,决定哪些行进入结果集
  • BETWEEN 是闭区间,IN 是集合匹配
  • NULL 只能用 IS NULL / IS NOT NULL 判断
  • WHERE 条件是索引优化的关键入口
  • WHERE 中不能使用 SELECT 中定义的别名

下一章引子:筛选出了目标行,接下来学习如何按你想要的顺序呈现结果。

上一页
SELECT
下一页
ORDER BY