分组数据【GROUP BY 与 HAVING的使用】

目录

[创建分组(GROUP BY子句)](#创建分组(GROUP BY子句))

过滤分组(HAVING子句)


本篇文章内容的前置知识为汇总数据(使用聚集函数),可点击链接学习:

汇总数据(使用聚集函数)-CSDN博客

创建分组(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_idprod_pricevend_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
作用时机 分组前筛选行 分组后筛选分组
作用对象 行数据 分组聚合结果
能否使用聚合函数 不能 可以
相关推荐
星星也在雾里8 小时前
PgBouncer 解决 PostgreSQL 连接数超限 + 可视化监控
数据库·postgresql
雨辰AI9 小时前
SpringBoot3 + 人大金仓读写分离 + 分库分表 + 集群高可用 全栈实战
java·数据库·mysql·政务
长城202410 小时前
关于MySql的ONLY_FULL_GROUP_BY问题
数据库·mysql·聚合列
常常有10 小时前
MySQL 底层执行原理:输入SQL语句到两阶段提交
数据库·sql·mysql
Mr. zhihao10 小时前
深入解析redis基本数据结构
数据结构·数据库·redis
m0_7488394910 小时前
利用天正暖通CAD快速掌握风管数量统计的方法
数据库
随身数智备忘录10 小时前
什么是设备管理体系?设备管理体系包含哪些核心模块?
网络·数据库·人工智能
海市公约11 小时前
MySQL更新语句执行全流程:从Buffer Pool修改到二阶段提交
数据库·mysql·binlog·innodb·undo log·二阶段提交·update执行原理
颂love12 小时前
MySQL的执行流程
android·数据库·mysql
海市公约12 小时前
一条SQL查询的完整旅程:MySQL执行流程深度解析
sql·mysql·数据库优化·执行计划·连接器·查询缓存·sql执行原理