分组数据【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
作用时机 分组前筛选行 分组后筛选分组
作用对象 行数据 分组聚合结果
能否使用聚合函数 不能 可以
相关推荐
forEverPlume9 小时前
PHP怎么使用Eloquent Attribute Composition属性组合_Laravel通过组合构建复杂属性【方法】
jvm·数据库·python
2301_8092047010 小时前
mysql在docker容器中如何部署_利用docker-compose快速启动
jvm·数据库·python
虹科网络安全10 小时前
艾体宝产品|深度解读 Redis 8.4 新增功能:原子化 Slot 迁移(上)
数据库·redis·bootstrap
阿坤带你走近大数据10 小时前
怎么查看当前oracle库下的表空间temp大小或者默认大小
数据库·oracle
yoyo_zzm10 小时前
Laravel8.x新特性全解析
数据库·nginx
码界奇点11 小时前
基于Python的新浪微博数据爬虫系统设计与实现
数据库·爬虫·python·毕业设计·新浪微博·源代码管理
我科绝伦(Huanhuan Zhou)12 小时前
探索技术世界:我的GitHub数据库工具宝库
数据库·github
猫的玖月12 小时前
(一)MY SQL概述
数据库·sql
脑子进水养啥鱼?13 小时前
PostgreSQL .history 文件
数据库·postgresql
倔强的石头_13 小时前
5 个真实案例带你避坑:DolphinDB 实时写入、流订阅与高可用调优
数据库