sql-having-clause
SQL HAVING 子句
Section titled “SQL HAVING 子句”1. SQL HAVING 子句的用途
Section titled “1. SQL HAVING 子句的用途”SQL HAVING 子句用于根据聚合函数(aggregate functions)过滤查询结果。WHERE 子句在任何分组发生之前过滤单行数据,而 HAVING 子句则在数据通过 GROUP BY 子句聚合之后过滤整个行组。因此,HAVING 子句几乎总是与 GROUP BY 一起使用。
您可以在 HAVING 子句中使用标准的聚合函数,如 COUNT()、SUM()、AVG()、MIN() 和 MAX(),来为数据组指定条件。
2. HAVING 与 WHERE 的区别
Section titled “2. HAVING 与 WHERE 的区别”对于初学者来说,这常常是一个容易混淆的地方。关键区别在于过滤过程发生的时间点:
- WHERE 子句在聚合之前过滤行。它作用于单个行数据。
- HAVING 子句在聚合之后过滤组。它作用于聚合函数的结果。
类比:想象一家餐厅。WHERE 子句就像服务员丢弃不符合某个标准的单个订单(例如,“不要洋葱”)。GROUP BY 子句就像按桌号对所有订单进行分组。HAVING 子句就像经理检查哪些桌子(组)的总账单(一个聚合值)超过 100 美元。
3. 语法和逻辑查询处理顺序
Section titled “3. 语法和逻辑查询处理顺序”包含 HAVING 子句的查询基本语法如下:
SELECT column_name(s), aggregate_function(column_name)FROM table_nameWHERE condition(s) -- 可选:在分组前过滤行GROUP BY column_name(s)HAVING condition(s) -- 组过滤的必需项ORDER BY column_name(s); -- 可选:对最终结果集进行排序理解数据库处理查询的逻辑顺序至关重要,因为这解释了为什么 HAVING 作用于聚合数据而 WHERE 不作用于聚合数据:
1. FROM / JOIN2. WHERE3. GROUP BY4. HAVING5. SELECT6. DISTINCT7. ORDER BY8. LIMIT / OFFSET / FETCH4. 聚合函数的实际应用示例
Section titled “4. 聚合函数的实际应用示例”让我们使用一个现代的 employees 表作为示例。该表存储员工的详细信息,包括他们的部门和薪资。
-- 设置:创建并填充 'employees' 表CREATE TABLE employees ( id INT PRIMARY KEY AUTO_INCREMENT, first_name VARCHAR(100) NOT NULL, last_name VARCHAR(100) NOT NULL, department VARCHAR(50) NOT NULL, salary DECIMAL(10, 2) NOT NULL);
INSERT INTO employees (first_name, last_name, department, salary) VALUES('Alice', 'Smith', 'Engineering', 95000.00),('Bob', 'Johnson', 'Engineering', 110000.00),('Charlie', 'Brown', 'HR', 60000.00),('Diana', 'Prince', 'Marketing', 75000.00),('Ethan', 'Hunt', 'Engineering', 125000.00),('Fiona', 'Glenanne', 'Marketing', 82000.00),('George', 'Costanza', 'Sales', 88000.00);将 HAVING 与 COUNT() 结合使用
Section titled “将 HAVING 与 COUNT() 结合使用”让我们找出员工数量多于一个的部门。
-- 查找员工数量为 2 人或更多的部门SELECT department, COUNT(id) AS number_of_employeesFROM employeesGROUP BY departmentHAVING COUNT(id) >= 2;| 部门 | 员工数量 |
|---|---|
| Engineering | 3 |
| Marketing | 2 |
将 HAVING 与 SUM() 和 AVG() 结合使用
Section titled “将 HAVING 与 SUM() 和 AVG() 结合使用”现在,让我们找出平均薪资超过 90,000 美元的部门。
-- 查找平均薪资超过 90,000 美元的部门SELECT department, AVG(salary) AS average_salaryFROM employeesGROUP BY departmentHAVING AVG(salary) > 90000.00;| 部门 | 平均薪资 |
|---|---|
| Engineering | 110000.00 |
将 HAVING 与 MIN() 和 MAX() 结合使用
Section titled “将 HAVING 与 MIN() 和 MAX() 结合使用”此查询查找最高薪资至少为 120,000 美元的部门。
-- 查找至少有一名员工薪资达到或超过 120,000 美元的部门SELECT department, MAX(salary) AS max_salary_in_deptFROM employeesGROUP BY departmentHAVING MAX(salary) >= 120000.00;| 部门 | 部门最高薪资 |
|---|---|
| Engineering | 125000.00 |
5. 将 HAVING 与 ORDER BY 结合使用
Section titled “5. 将 HAVING 与 ORDER BY 结合使用”ORDER BY 子句在 HAVING 子句之后应用,允许您对最终过滤后的组进行排序。让我们找出所有部门,计算它们的总薪资支出,然后只显示总支出超过 150,000 美元的部门,并按从高到低的顺序排序。
SELECT department, SUM(salary) AS total_payrollFROM employeesGROUP BY departmentHAVING SUM(salary) > 150000.00ORDER BY total_payroll DESC;| 部门 | 总薪资支出 |
|---|---|
| Engineering | 330000.00 |
6. 常见错误和最佳实践
Section titled “6. 常见错误和最佳实践”- 错误: 在
HAVING中使用不在GROUP BY中的非聚合列。这将在大多数 SQL 数据库中导致错误。 - 错误: 在
HAVING子句中使用SELECT列表中的别名。某些数据库(如 MySQL)支持此操作,但它不符合标准 SQL,在其他地方可能会失败。标准做法是重复聚合函数。 - 最佳实践: 在分组之前尽可能多地使用
WHERE进行过滤。WHERE子句减少了需要由GROUP BY和HAVING子句处理的行数,这更有效率。例如,如果您只关心“工程”部门的薪资,请首先使用WHERE department = 'Engineering'进行过滤。 - 最佳实践: 保持
HAVING子句简洁,并专注于聚合条件。复杂的逻辑通常可以使用公用表表达式(CTE)来简化。
7. 实际应用场景
Section titled “7. 实际应用场景”想象您是电子商务平台的数据分析师。一项常见的任务是识别高价值客户。您可以使用 HAVING 子句来查找下订单超过 5 个或总消费超过 1,000 美元的客户。
-- 查找高价值客户的伪代码SELECT customer_id, COUNT(order_id) AS total_orders, SUM(order_value) AS total_spentFROM ordersGROUP BY customer_idHAVING COUNT(order_id) > 5 OR SUM(order_value) > 1000.00ORDER BY total_spent DESC;