WHERE条件查询
哪吒 2024/1/1
# WHERE条件查询
点击勘误issues (opens new window),哪吒感谢大家的阅读
# WHERE子句概述
WHERE子句用于过滤记录,只返回满足指定条件的行。它是SQL查询中最重要的子句之一,可以大大提高查询的精确性和效率。
# 基本语法
SELECT 列名1, 列名2, ...
FROM 表名
WHERE 条件表达式;
# 比较运算符
# 1. 等于 (=)
-- 查询薪资等于8000的员工
SELECT * FROM employees WHERE salary = 8000;
-- 查询部门为IT的员工
SELECT name, position FROM employees WHERE department = 'IT';
# 2. 不等于 (!= 或 <>)
-- 查询薪资不等于8000的员工
SELECT * FROM employees WHERE salary != 8000;
SELECT * FROM employees WHERE salary <> 8000;
-- 查询不是IT部门的员工
SELECT * FROM employees WHERE department != 'IT';
# 3. 大于 (>) 和小于 (<)
-- 查询薪资大于10000的员工
SELECT name, salary FROM employees WHERE salary > 10000;
-- 查询年龄小于30的员工
SELECT name, age FROM employees WHERE age < 30;
# 4. 大于等于 (>=) 和小于等于 (<=)
-- 查询薪资大于等于8000的员工
SELECT * FROM employees WHERE salary >= 8000;
-- 查询年龄小于等于25的员工
SELECT * FROM employees WHERE age <= 25;
# 逻辑运算符
# 1. AND运算符
-- 查询IT部门且薪资大于8000的员工
SELECT * FROM employees
WHERE department = 'IT' AND salary > 8000;
-- 查询年龄在25-35之间的员工
SELECT * FROM employees
WHERE age >= 25 AND age <= 35;
-- 多个AND条件
SELECT * FROM employees
WHERE department = 'IT'
AND salary > 8000
AND hire_date > '2020-01-01';
# 2. OR运算符
-- 查询IT部门或HR部门的员工
SELECT * FROM employees
WHERE department = 'IT' OR department = 'HR';
-- 查询薪资小于5000或大于15000的员工
SELECT * FROM employees
WHERE salary < 5000 OR salary > 15000;
# 3. NOT运算符
-- 查询不是IT部门的员工
SELECT * FROM employees
WHERE NOT department = 'IT';
-- 查询薪资不在8000-12000之间的员工
SELECT * FROM employees
WHERE NOT (salary >= 8000 AND salary <= 12000);
# 4. 运算符优先级
-- 使用括号明确优先级
SELECT * FROM employees
WHERE (department = 'IT' OR department = 'HR')
AND salary > 8000;
-- 等价于上面的查询
SELECT * FROM employees
WHERE department = 'IT' AND salary > 8000
OR department = 'HR' AND salary > 8000;
# 范围查询
# 1. BETWEEN运算符
-- 查询薪资在8000-12000之间的员工
SELECT * FROM employees
WHERE salary BETWEEN 8000 AND 12000;
-- 查询入职日期在2020年的员工
SELECT * FROM employees
WHERE hire_date BETWEEN '2020-01-01' AND '2020-12-31';
-- NOT BETWEEN
SELECT * FROM employees
WHERE salary NOT BETWEEN 8000 AND 12000;
# 2. IN运算符
-- 查询特定部门的员工
SELECT * FROM employees
WHERE department IN ('IT', 'HR', 'Finance');
-- 查询特定ID的员工
SELECT * FROM employees
WHERE id IN (1, 3, 5, 7);
-- NOT IN
SELECT * FROM employees
WHERE department NOT IN ('IT', 'HR');
# 模式匹配
# 1. LIKE运算符
-- 查询姓名以'张'开头的员工
SELECT * FROM employees WHERE name LIKE '张%';
-- 查询姓名以'三'结尾的员工
SELECT * FROM employees WHERE name LIKE '%三';
-- 查询姓名包含'小'的员工
SELECT * FROM employees WHERE name LIKE '%小%';
-- 查询姓名为两个字的员工
SELECT * FROM employees WHERE name LIKE '__';
-- 查询邮箱是gmail的员工
SELECT * FROM employees WHERE email LIKE '%@gmail.com';
# 2. 通配符说明
%
:匹配零个或多个字符_
:匹配单个字符[]
:匹配括号内的任意单个字符(SQL Server)[^]
:匹配不在括号内的任意单个字符(SQL Server)
-- SQL Server示例
SELECT * FROM employees WHERE name LIKE '[张李王]%';
SELECT * FROM employees WHERE name LIKE '[^张李王]%';
# 3. REGEXP/RLIKE(MySQL)
-- 使用正则表达式查询
SELECT * FROM employees WHERE name REGEXP '^张.*三$';
-- 查询邮箱格式正确的员工
SELECT * FROM employees
WHERE email REGEXP '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$';
# NULL值处理
# 1. IS NULL和IS NOT NULL
-- 查询没有邮箱的员工
SELECT * FROM employees WHERE email IS NULL;
-- 查询有邮箱的员工
SELECT * FROM employees WHERE email IS NOT NULL;
-- 查询没有部门分配的员工
SELECT * FROM employees WHERE department IS NULL;
# 2. NULL值的特殊性
-- 错误:NULL不能用=比较
SELECT * FROM employees WHERE email = NULL; -- 返回空结果
-- 正确:使用IS NULL
SELECT * FROM employees WHERE email IS NULL;
-- NULL参与的运算结果都是NULL
SELECT * FROM employees WHERE salary + NULL > 10000; -- 返回空结果
# 日期时间查询
# 1. 日期比较
-- 查询2020年后入职的员工
SELECT * FROM employees WHERE hire_date > '2020-01-01';
-- 查询今年入职的员工
SELECT * FROM employees WHERE YEAR(hire_date) = YEAR(CURDATE());
-- 查询本月入职的员工
SELECT * FROM employees
WHERE YEAR(hire_date) = YEAR(CURDATE())
AND MONTH(hire_date) = MONTH(CURDATE());
# 2. 日期函数在WHERE中的应用
-- 查询工作超过3年的员工
SELECT * FROM employees
WHERE DATEDIFF(CURDATE(), hire_date) > 365 * 3;
-- 查询本周入职的员工
SELECT * FROM employees
WHERE YEARWEEK(hire_date) = YEARWEEK(CURDATE());
-- 查询生日在本月的员工
SELECT * FROM employees
WHERE MONTH(birthday) = MONTH(CURDATE());
# 子查询在WHERE中的应用
# 1. 单值子查询
-- 查询薪资高于平均薪资的员工
SELECT * FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
-- 查询与张三同部门的员工
SELECT * FROM employees
WHERE department = (SELECT department FROM employees WHERE name = '张三');
# 2. 多值子查询
-- 查询薪资在前3名的员工
SELECT * FROM employees
WHERE salary IN (
SELECT DISTINCT salary FROM employees
ORDER BY salary DESC LIMIT 3
);
-- 查询有下属的管理者
SELECT * FROM employees
WHERE id IN (SELECT DISTINCT manager_id FROM employees WHERE manager_id IS NOT NULL);
# 3. EXISTS子查询
-- 查询有订单的客户
SELECT * FROM customers c
WHERE EXISTS (
SELECT 1 FROM orders o WHERE o.customer_id = c.id
);
-- 查询没有订单的客户
SELECT * FROM customers c
WHERE NOT EXISTS (
SELECT 1 FROM orders o WHERE o.customer_id = c.id
);
# 实战案例
假设我们有以下员工表:
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(100),
department VARCHAR(50),
position VARCHAR(50),
salary DECIMAL(10,2),
hire_date DATE,
manager_id INT,
email VARCHAR(100)
);
# 复杂查询示例
-- 1. 查询IT部门中薪资在8000-15000之间,且入职超过2年的程序员
SELECT name, salary, hire_date
FROM employees
WHERE department = 'IT'
AND salary BETWEEN 8000 AND 15000
AND position LIKE '%程序员%'
AND DATEDIFF(CURDATE(), hire_date) > 730;
-- 2. 查询薪资高于其所在部门平均薪资的员工
SELECT e1.name, e1.department, e1.salary
FROM employees e1
WHERE e1.salary > (
SELECT AVG(e2.salary)
FROM employees e2
WHERE e2.department = e1.department
);
-- 3. 查询没有邮箱或邮箱不是公司邮箱的员工
SELECT name, email
FROM employees
WHERE email IS NULL
OR email NOT LIKE '%@company.com';
-- 4. 查询同时满足以下条件的员工:
-- - 不是管理者
-- - 薪资在部门前50%
-- - 入职时间在工作日
SELECT name, department, salary, hire_date
FROM employees e1
WHERE e1.id NOT IN (
SELECT DISTINCT manager_id
FROM employees
WHERE manager_id IS NOT NULL
)
AND e1.salary >= (
SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY salary)
FROM employees e2
WHERE e2.department = e1.department
)
AND DAYOFWEEK(e1.hire_date) BETWEEN 2 AND 6;
# 性能优化技巧
# 1. 索引优化
-- 在经常用于WHERE条件的列上创建索引
CREATE INDEX idx_department ON employees(department);
CREATE INDEX idx_salary ON employees(salary);
CREATE INDEX idx_hire_date ON employees(hire_date);
-- 复合索引
CREATE INDEX idx_dept_salary ON employees(department, salary);
# 2. 查询优化
-- 优化前:函数作用在列上
SELECT * FROM employees WHERE YEAR(hire_date) = 2020;
-- 优化后:避免在列上使用函数
SELECT * FROM employees
WHERE hire_date >= '2020-01-01' AND hire_date < '2021-01-01';
-- 优化前:OR条件
SELECT * FROM employees WHERE department = 'IT' OR department = 'HR';
-- 优化后:使用IN
SELECT * FROM employees WHERE department IN ('IT', 'HR');
# 3. 避免全表扫描
-- 避免:前导通配符
SELECT * FROM employees WHERE name LIKE '%张%';
-- 推荐:后导通配符(可以使用索引)
SELECT * FROM employees WHERE name LIKE '张%';
-- 避免:NOT条件
SELECT * FROM employees WHERE department != 'IT';
-- 推荐:使用IN列出所有可能值
SELECT * FROM employees WHERE department IN ('HR', 'Finance', 'Marketing');
# 常见错误
# 1. NULL值比较错误
-- 错误
SELECT * FROM employees WHERE email = NULL;
-- 正确
SELECT * FROM employees WHERE email IS NULL;
# 2. 字符串比较错误
-- 错误:数字当字符串比较
SELECT * FROM employees WHERE salary = '8000';
-- 正确:数字比较
SELECT * FROM employees WHERE salary = 8000;
# 3. 日期格式错误
-- 错误:日期格式不标准
SELECT * FROM employees WHERE hire_date = '2020/1/1';
-- 正确:标准日期格式
SELECT * FROM employees WHERE hire_date = '2020-01-01';
# 4. 逻辑运算符优先级错误
-- 可能不是预期结果
SELECT * FROM employees
WHERE department = 'IT' OR department = 'HR' AND salary > 8000;
-- 明确优先级
SELECT * FROM employees
WHERE (department = 'IT' OR department = 'HR') AND salary > 8000;
# 总结
WHERE子句是SQL查询的核心,掌握各种条件表达式的使用方法对于编写高效的SQL查询至关重要。关键要点:
- 熟练掌握各种比较和逻辑运算符
- 正确处理NULL值
- 合理使用通配符和模式匹配
- 注意运算符优先级
- 考虑查询性能优化
- 避免常见的语法错误