SQL关键字详解:WHERE、GROUP BY、HAVING、ORDER BY、LIMIT的区别与用法

作者:c_chun 发布时间: 2025-08-31 阅读量:13 评论数:0

很多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');

我们的数据表长这样:

id

name

department

salary

age

hire_date

1

张三

技术部

8000

28

2022-01-15

2

李四

销售部

6000

25

2022-03-10

3

王五

技术部

12000

32

2021-06-20

4

赵六

销售部

7000

29

2022-02-14

5

钱七

技术部

9000

26

2023-01-08

6

孙八

人事部

5500

24

2022-05-12

7

周九

人事部

6500

30

2021-09-03

8

吴十

销售部

8500

27

2022-07-18

WHERE:数据过滤器

作用:在查询时过滤行数据,只要符合条件的记录。

基础用法

例子1:查找技术部的员工

SELECT * FROM employees 
WHERE department = '技术部';

返回结果:

id

name

department

salary

age

hire_date

1

张三

技术部

8000

28

2022-01-15

3

王五

技术部

12000

32

2021-06-20

5

钱七

技术部

9000

26

2023-01-08

例子2:查找薪资大于7000的员工

SELECT name, salary FROM employees 
WHERE salary > 7000;

返回结果:

name

salary

张三

8000

王五

12000

钱七

9000

吴十

8500

复合条件

例子3:查找技术部且薪资大于8000的员工

SELECT * FROM employees 
WHERE department = '技术部' AND salary > 8000;

返回结果:

id

name

department

salary

age

hire_date

3

王五

技术部

12000

32

2021-06-20

5

钱七

技术部

9000

26

2023-01-08

GROUP BY:数据分组

作用:将数据按指定字段分组,通常配合聚合函数使用。

基础分组

例子1:按部门分组,统计每个部门的人数

SELECT department, COUNT(*) as employee_count
FROM employees 
GROUP BY department;

返回结果:

department

employee_count

技术部

3

销售部

3

人事部

2

例子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;

返回结果:

department

employee_count

avg_salary

max_salary

min_salary

技术部

3

9666.67

12000

8000

销售部

3

7166.67

8500

6000

人事部

2

6000.00

6500

5500

多字段分组

例子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;

返回结果:

department

age_group

count

技术部

年轻组

1

技术部

中年组

1

技术部

资深组

1

销售部

年轻组

1

销售部

中年组

2

人事部

年轻组

1

人事部

资深组

1

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;

返回结果:

department

avg_salary

employee_count

技术部

9666.67

3

销售部

7166.67

3

例子2:查找人数大于2的部门

SELECT department, COUNT(*) as employee_count
FROM employees 
GROUP BY department 
HAVING COUNT(*) > 2;

返回结果:

department

employee_count

技术部

3

销售部

3

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;

返回结果:

department

avg_salary

employee_count

销售部

7166.67

3

执行过程分析:

  1. WHERE:先筛选出2022年入职的员工(6个人)

  2. GROUP BY:将这6个人按部门分组

  3. HAVING:从分组结果中筛选平均薪资>7000的部门

ORDER BY:结果排序

作用:对查询结果进行排序。

基础排序

例子1:按薪资从高到低排序

SELECT name, salary 
FROM employees 
ORDER BY salary DESC;

返回结果:

name

salary

王五

12000

钱七

9000

吴十

8500

张三

8000

赵六

7000

周九

6500

李四

6000

孙八

5500

例子2:按年龄升序排序

SELECT name, age 
FROM employees 
ORDER BY age ASC;  -- ASC可以省略,默认就是升序

返回结果:

name

age

孙八

24

李四

25

钱七

26

吴十

27

张三

28

赵六

29

周九

30

王五

32

多字段排序

例子3:先按部门排序,再按薪资排序

SELECT name, department, salary 
FROM employees 
ORDER BY department ASC, salary DESC;

返回结果:

name

department

salary

周九

人事部

6500

孙八

人事部

5500

王五

技术部

12000

钱七

技术部

9000

张三

技术部

8000

吴十

销售部

8500

赵六

销售部

7000

李四

销售部

6000

分组后排序

例子4:各部门平均薪资,按平均薪资排序

SELECT department, AVG(salary) as avg_salary
FROM employees 
GROUP BY department 
ORDER BY avg_salary DESC;

返回结果:

department

avg_salary

技术部

9666.67

销售部

7166.67

人事部

6000.00

LIMIT:结果数量限制

作用:限制查询返回的记录数量。

基础用法

例子1:查询薪资最高的3名员工

SELECT name, salary 
FROM employees 
ORDER BY salary DESC 
LIMIT 3;

返回结果:

name

salary

王五

12000

钱七

9000

吴十

8500

例子2:分页查询(跳过前3条,取接下来的2条)

SELECT name, salary 
FROM employees 
ORDER BY salary DESC 
LIMIT 2 OFFSET 3;
-- 或者写成:LIMIT 3, 2  (MySQL语法)

返回结果:

name

salary

张三

8000

赵六

7000

实际应用场景

例子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;

返回结果:

name

department

salary

王五

技术部

12000

吴十

销售部

8500

周九

人事部

6500

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年入职的员工:

name

department

salary

张三

技术部

8000

李四

销售部

6000

赵六

销售部

7000

孙八

人事部

5500

周九

人事部

6500

吴十

销售部

8500

步骤2:GROUP BY分组 按部门分组并计算聚合函数:

department

avg_salary

employee_count

技术部

8000.00

1

销售部

7166.67

3

人事部

6000.00

2

步骤3:HAVING过滤 筛选平均薪资>6500的部门:

department

avg_salary

employee_count

技术部

8000.00

1

销售部

7166.67

3

步骤4:ORDER BY排序 按平均薪资降序:

department

avg_salary

employee_count

技术部

8000.00

1

销售部

7166.67

3

步骤5:LIMIT限制 取前2名(本例中只有2条记录,所以结果不变)

最终返回结果:

department

avg_salary

employee_count

技术部

8000.00

1

销售部

7166.67

3

各关键字详细对比

WHERE vs HAVING

对比项

WHERE

HAVING

作用时机

分组前过滤

分组后过滤

过滤对象

原始行数据

分组结果

可用函数

不能使用聚合函数

可以使用聚合函数

执行顺序

第2步

第4步

错误示例:

-- ❌ 错误: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查询语句了!


评论