分组数据【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
作用时机 分组前筛选行 分组后筛选分组
作用对象 行数据 分组聚合结果
能否使用聚合函数 不能 可以
相关推荐
流星白龙24 分钟前
【MySQL高阶】26.事务(1)
数据库·mysql
三十..1 小时前
Redis 核心原理与高可用架构实践
运维·数据库·redis
这个DBA有点耶1 小时前
索引优化深潜(下):索引合并、ICP 与索引设计的实战法则
数据库·mysql·架构
努力努力再努力wz2 小时前
【内存管理与高并发内存池系列】从 mmap 到 malloc:文件映射、匿名映射与 glibc 内存分配机制详解
linux·c语言·数据结构·数据库·c++·qt·链表
Theo·Chan2 小时前
机房断电搞崩服务器 | 人大金仓 V8 全量备份跨实例完整恢复实录
sql·信创·kingbase·金仓
JdSnE27zv2 小时前
Qt 操作SQLite数据库
数据库·qt·sqlite
tedcloud1232 小时前
HyperFrames部署教程:用HTML生成MP4视频
前端·数据库·人工智能·html·音视频
布朗克1682 小时前
25 IO流高级操作——序列化、NIO与Files工具类
java·数据库·io·nio
阿演2 小时前
DataDjinn 新版本更新:新增 Oracle 支持,查询窗口、表预览和连接树继续打磨
数据库·oracle·ai编程·数据库连接工具
lixora3 小时前
Oracle 11g Active Data Guard Go 自动化部署工具 v1.0
数据库·oracle