分组数据【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
作用时机 分组前筛选行 分组后筛选分组
作用对象 行数据 分组聚合结果
能否使用聚合函数 不能 可以
相关推荐
IvorySQL4 小时前
PostgreSQL 日报| PostgreSQL 19 默认 WAL 压缩算法(8 月 8 日)
数据库·postgresql·区块链
油丶酸萝卜别吃4 小时前
MySQL B+ 树查询全过程详解
数据库·mysql
leisoo80974 小时前
股票数据本地化存储实战:JSON、数据库与列式存储的方案对比
jvm·数据库·json
Exclusive_Cat5 小时前
MySQL回表机制解析与优化策略
数据库·sql
circuitsosk5 小时前
向量数据库选型与性能压测:Milvus、Pinecone、Chroma在真实业务下的对比
数据库·python·pinecone·milvus·向量数据库·chroma
影寂ldy5 小时前
SQL 索引(Index)完整笔记
数据库·笔记·sql
切糕师学AI5 小时前
从压缩到查询:PostgreSQL中JSON数据的存储与处理实践
数据库·postgresql·json
渣渣盟5 小时前
当 Redis 写入成为性能瓶颈时,如何利用 异步批量 Sink 将吞吐量从 1w QPS 提升到 10w+?
数据库·redis·php
SelectDB5 小时前
Apache Doris 2026 Roadmap:AI 成为主流负载后数据基础设施的演进方向
数据库
SelectDB5 小时前
瓴岳科技洋钱罐 SelectDB Hive 透明加速:湖仓一体化探索分析平台升级实践
数据库