分组数据【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
作用时机 分组前筛选行 分组后筛选分组
作用对象 行数据 分组聚合结果
能否使用聚合函数 不能 可以
相关推荐
前端世界1 分钟前
MySQL 基础入门(学习第4天)——约束与 DML 操作详解
数据库·学习·mysql
nianniannnn1 小时前
Qt QMessageBox知识点
开发语言·数据库·qt
—Miss. Z—1 小时前
计算机二级MySQL——简单应用题(存储过程&存储函数)
数据库·oracle·php
Csvn2 小时前
📊 SQL 入门 Day 9:CTE(公用表表达式)— 让 SQL 像写代码一样优雅
后端·sql
Vect__2 小时前
MySQL 数据类型和约束:从字段设计到表结构建模
数据库·mysql
糖果店的幽灵2 小时前
langgraph的分支结构之 - 静态分支详解
java·服务器·数据库·langgraph
虹科网络安全2 小时前
艾体宝新闻|从 SQL 注入到服务器接管:CVE-2026-57517 暴露 Web 管理面板的供应链与安全编码风险
服务器·前端·sql
张人玉2 小时前
C# WinForms——工厂管理系统(C# WinForms)
数据库·sqlite·c#·winform
AC赳赳老秦3 小时前
招投标公开数据自动化采集实战:基于 OpenClaw 的定时抓取与业务关键词精准推送
运维·服务器·数据库·自动化·测试用例·deepseek·openclaw
后端优选官4 小时前
上海Agent开发公司:企业级智能体软件的技术架构与落地评估
数据库·人工智能·架构·软件开发·开发经验·上海