目录
[创建分组(GROUP BY子句)](#创建分组(GROUP BY子句))
本篇文章内容的前置知识为汇总数据(使用聚集函数),可点击链接学习:
创建分组(GROUP BY子句)
1. 基础语法
通过在SELECT语句中使用GROUP BY子句来创建分组。
GROUP BY 通常和聚合函数搭配使用,否则分组的意义不大
要求:统计各供应商的产品数量
sql
SELECT vend_id, COUNT(*) AS num_prods
FROM products
GROUP BY vend_id;
2. GROUP BY 子句的重要规则
(1)SELECT 里非聚合的列,必须全部出现在 GROUP BY 里
| 字段类型 | 定义 | 例子 |
|---|---|---|
| 普通字段(非聚合字段) | 直接从表中取出的原始列,或基于原始列的表达式,描述单条记录的属性 | vend_id、prod_price、vend_id*2 |
| 聚合字段 | 通过聚合函数计算得到的列,描述一组记录的统计结果 | COUNT(*)、SUM(prod_price)、AVG(prod_price) |
Q:为什么SELECT 里的普通字段必须出现在 GROUP BY 里?
举个反例:
sql
SELECT vend_id, prod_name, COUNT(*)
FROM products
GROUP BY vend_id;
GROUP BY 的本质是将多条记录合并成一行
GROUP BY vend_id 会把供应商100 的所有商品合并成一行
但供应商100 可能有多个 prod_name,数据库无法确定这一行该显示哪个 prod_name,没有规则能判断,所以只能报错。
正确写法如下:
sql
SELECT vend_id, prod_name, COUNT(*)
FROM products
GROUP BY vend_id, prod_name;
(2)GROUP BY 可以多列分组,多列是组合键(按组合值分组)
比如上面的GROUP BY vend_id, prod_name;数据库会按 vend_id 和 prod_name 列进行复合分组,将 vend_id 和 prod_name 的值完全相同的记录归为同一个分组,然后对每个分组执行聚合计算。
(3)GROUP BY 不能用聚合函数、不能用列别名,要用原表达式
sql
SELECT vend_id, prod_price * 0.8 AS discount_price, COUNT(*)
FROM products
GROUP BY vend_id, prod_price * 0.8;
(4)GROUP BY 书写顺序:WHERE 后、ORDER BY 前
SQL 子句的书写顺序是 SELECT、FROM、WHERE、GROUP BY、HAVING、ORDER BY
过滤分组(HAVING子句)
Q:为什么需要过滤分组?
A:使用 GROUP BY 可以将数据分组,但有时我们需要对分组后的结果再进行筛选,但WHERE 子句只能在分组前筛选行,无法对分组后的结果进行过滤,因此需要新的工具。
HAVING 子句用于分组后筛选分组,通常与GROUP BY配合使用
创建一个订单表如下:
sql
-- 创建orders订单表
CREATE TABLE orders (
order_id INT PRIMARY KEY AUTO_INCREMENT, -- 订单ID(主键,自增)
cust_id INT NOT NULL, -- 客户ID(用于分组)
order_date DATE NOT NULL, -- 下单日期
order_amount DECIMAL(10,2) NOT NULL -- 订单金额
);
INSERT INTO Orders (cust_id, order_date, order_amount) VALUES
(101, '2026-01-05', 199.00),
(101, '2026-01-12', 299.00), -- 客户101:第2个订单
(101, '2026-01-20', 89.00), -- 客户101:第3个订单
(102, '2026-01-08', 699.00),
(102, '2026-01-18', 399.00), -- 客户102:第2个订单
(103, '2026-01-10', 1299.00), -- 客户103:仅1个订单
(104, '2026-01-15', 499.00),
(104, '2026-01-22', 899.00), -- 客户104:第2个订单
(105, '2026-01-03', 59.00); -- 客户105:仅1个订单
DATE 标准格式是 YYYY-MM-DD
要求:统计至少有 2 个订单的客户
sql
SELECT cust_id, COUNT(*) AS orders
FROM orders
GROUP BY cust_id
HAVING COUNT(*) >= 2;
HAVING 与 WHERE 的区别
| 特性 | WHERE | HAVING |
|---|---|---|
| 作用时机 | 分组前筛选行 | 分组后筛选分组 |
| 作用对象 | 行数据 | 分组聚合结果 |
| 能否使用聚合函数 | 不能 | 可以 |