很多SQL初学者都会被这些关键字搞混:WHERE、GROUP BY、HAVING、ORDER BY、LIMIT...它们到底有什么区别?什么时候用哪个?
今天我们用一个完整的例子,彻底搞清楚这些关键字的用法和执行顺序。
示例数据表
为了让例子更直观,我们先创建一个员工表(employees):
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(50),
department VARCHAR(50),
salary DECIMAL(10,2),
age INT,
hire_date DATE
);
INSERT INTO employees VALUES
(1, '张三', '技术部', 8000.00, 28, '2022-01-15'),
(2, '李四', '销售部', 6000.00, 25, '2022-03-10'),
(3, '王五', '技术部', 12000.00, 32, '2021-06-20'),
(4, '赵六', '销售部', 7000.00, 29, '2022-02-14'),
(5, '钱七', '技术部', 9000.00, 26, '2023-01-08'),
(6, '孙八', '人事部', 5500.00, 24, '2022-05-12'),
(7, '周九', '人事部', 6500.00, 30, '2021-09-03'),
(8, '吴十', '销售部', 8500.00, 27, '2022-07-18');
我们的数据表长这样:
WHERE:数据过滤器
作用:在查询时过滤行数据,只要符合条件的记录。
基础用法
例子1:查找技术部的员工
SELECT * FROM employees
WHERE department = '技术部';
返回结果:
例子2:查找薪资大于7000的员工
SELECT name, salary FROM employees
WHERE salary > 7000;
返回结果:
复合条件
例子3:查找技术部且薪资大于8000的员工
SELECT * FROM employees
WHERE department = '技术部' AND salary > 8000;
返回结果:
GROUP BY:数据分组
作用:将数据按指定字段分组,通常配合聚合函数使用。
基础分组
例子1:按部门分组,统计每个部门的人数
SELECT department, COUNT(*) as employee_count
FROM employees
GROUP BY department;
返回结果:
例子2:按部门分组,计算每个部门的平均薪资
SELECT department,
COUNT(*) as employee_count,
AVG(salary) as avg_salary,
MAX(salary) as max_salary,
MIN(salary) as min_salary
FROM employees
GROUP BY department;
返回结果:
多字段分组
例子3:按部门和年龄段分组
SELECT department,
CASE
WHEN age < 26 THEN '年轻组'
WHEN age BETWEEN 26 AND 30 THEN '中年组'
ELSE '资深组'
END as age_group,
COUNT(*) as count
FROM employees
GROUP BY department, age_group;
返回结果:
HAVING:分组后的过滤器
作用:对GROUP BY的结果进行过滤,类似WHERE,但用于分组后的数据。
WHERE vs HAVING的区别:
WHERE:在分组前过滤行
HAVING:在分组后过滤组
基础用法
例子1:查找平均薪资大于7000的部门
SELECT department,
AVG(salary) as avg_salary,
COUNT(*) as employee_count
FROM employees
GROUP BY department
HAVING AVG(salary) > 7000;
返回结果:
例子2:查找人数大于2的部门
SELECT department, COUNT(*) as employee_count
FROM employees
GROUP BY department
HAVING COUNT(*) > 2;
返回结果:
WHERE + GROUP BY + HAVING 组合
例子3:查找2022年入职的员工中,平均薪资大于7000的部门
SELECT department,
AVG(salary) as avg_salary,
COUNT(*) as employee_count
FROM employees
WHERE hire_date >= '2022-01-01' AND hire_date < '2023-01-01'
GROUP BY department
HAVING AVG(salary) > 7000;
返回结果:
执行过程分析:
WHERE:先筛选出2022年入职的员工(6个人)
GROUP BY:将这6个人按部门分组
HAVING:从分组结果中筛选平均薪资>7000的部门
ORDER BY:结果排序
作用:对查询结果进行排序。
基础排序
例子1:按薪资从高到低排序
SELECT name, salary
FROM employees
ORDER BY salary DESC;
返回结果:
例子2:按年龄升序排序
SELECT name, age
FROM employees
ORDER BY age ASC; -- ASC可以省略,默认就是升序
返回结果:
多字段排序
例子3:先按部门排序,再按薪资排序
SELECT name, department, salary
FROM employees
ORDER BY department ASC, salary DESC;
返回结果:
分组后排序
例子4:各部门平均薪资,按平均薪资排序
SELECT department, AVG(salary) as avg_salary
FROM employees
GROUP BY department
ORDER BY avg_salary DESC;
返回结果:
LIMIT:结果数量限制
作用:限制查询返回的记录数量。
基础用法
例子1:查询薪资最高的3名员工
SELECT name, salary
FROM employees
ORDER BY salary DESC
LIMIT 3;
返回结果:
例子2:分页查询(跳过前3条,取接下来的2条)
SELECT name, salary
FROM employees
ORDER BY salary DESC
LIMIT 2 OFFSET 3;
-- 或者写成:LIMIT 3, 2 (MySQL语法)
返回结果:
实际应用场景
例子3:查询每个部门薪资最高的员工
-- 使用窗口函数(高级用法)
SELECT name, department, salary
FROM (
SELECT name, department, salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) as rn
FROM employees
) ranked
WHERE rn = 1;
返回结果:
SQL语句执行顺序
理解执行顺序很重要,这决定了各个关键字的使用规则:
1. FROM - 确定数据源
2. WHERE - 过滤行数据
3. GROUP BY - 数据分组
4. HAVING - 过滤分组结果
5. SELECT - 选择字段
6. ORDER BY - 结果排序
7. LIMIT - 限制结果数量
完整例子:所有关键字组合使用
需求:查找2022年入职的员工中,各部门平均薪资超过6500的部门,按平均薪资降序排列,只显示前2名
SELECT department,
AVG(salary) as avg_salary,
COUNT(*) as employee_count
FROM employees
WHERE hire_date >= '2022-01-01' AND hire_date < '2023-01-01' -- 1. 过滤2022年入职
GROUP BY department -- 2. 按部门分组
HAVING AVG(salary) > 6500 -- 3. 平均薪资>6500
ORDER BY avg_salary DESC -- 4. 按平均薪资降序
LIMIT 2; -- 5. 只要前2名
执行过程分析:
步骤1:WHERE过滤 筛选出2022年入职的员工:
步骤2:GROUP BY分组 按部门分组并计算聚合函数:
步骤3:HAVING过滤 筛选平均薪资>6500的部门:
步骤4:ORDER BY排序 按平均薪资降序:
步骤5:LIMIT限制 取前2名(本例中只有2条记录,所以结果不变)
最终返回结果:
各关键字详细对比
WHERE vs HAVING
错误示例:
-- ❌ 错误:WHERE中不能使用聚合函数
SELECT department, AVG(salary)
FROM employees
WHERE AVG(salary) > 7000 -- 这会报错!
GROUP BY department;
-- ✅ 正确:应该用HAVING
SELECT department, AVG(salary)
FROM employees
GROUP BY department
HAVING AVG(salary) > 7000;
GROUP BY使用注意事项
规则:SELECT中的字段,要么在GROUP BY中,要么是聚合函数
错误示例:
-- ❌ 错误:name字段既不在GROUP BY中,也不是聚合函数
SELECT department, name, COUNT(*)
FROM employees
GROUP BY department;
正确示例:
-- ✅ 正确:只选择分组字段和聚合函数
SELECT department, COUNT(*) as employee_count
FROM employees
GROUP BY department;
-- ✅ 正确:name字段也在GROUP BY中
SELECT department, name, salary
FROM employees
GROUP BY department, name;
总结
今天我们详细学习了SQL中5个重要关键字的用法:
🎯 核心要点:
WHERE:行级过滤,在分组前执行
GROUP BY:数据分组,配合聚合函数使用
HAVING:组级过滤,在分组后执行
ORDER BY:结果排序,几乎总是在最后执行
LIMIT:限制结果数量,用于分页和Top-N查询
📝 执行顺序记忆口诀: "From Where Group Having Select Order Limit" (从哪WHERE分组HAVING选择ORDER限制)
💡 实用建议:
先写WHERE过滤数据,减少GROUP BY的计算量
HAVING只用于过滤聚合结果
ORDER BY配合LIMIT可以高效获取Top-N结果
合理使用索引提升查询性能
掌握了这些概念和用法,你就能写出高效、准确的SQL查询语句了!