SQLSERVER分组
在 SQL Server 中,分组(Grouping) 主要通过 GROUP BY
子句实现,用于将结果集按一个或多个列的值进行 “分组”,并对每个分组应用聚合函数(如 COUNT
、SUM
、AVG
等)进行统计分析。分组是处理 “按类别汇总数据” 的核心手段(如 “按部门统计员工数量”“按地区汇总销售额” 等)。
一、基本语法与核心逻辑
GROUP BY
的核心逻辑是:将列值相同的行归为一组,然后对每组计算聚合结果。
1. 基础语法
SELECT 分组列1, 分组列2..., 聚合函数(列名) AS 别名 FROM 表名 WHERE 行筛选条件 -- 分组前筛选行 GROUP BY 分组列1, 分组列2... -- 按指定列分组 [HAVING 分组筛选条件]; -- 分组后筛选分组结果
2. 关键规则
SELECT
列表中非聚合函数的列,必须全部出现在GROUP BY
中(否则会报错)。分组后的数据顺序不确定,如需排序需加
ORDER BY
。
二、常用场景与示例
假设存在 Sales
表(销售记录),结构如下:
order_id | product | region | amount | sale_date |
---|---|---|---|---|
1 | 手机 | 华北 | 3000 | 2023-01-01 |
2 | 电脑 | 华北 | 5000 | 2023-01-02 |
3 | 手机 | 华东 | 3000 | 2023-01-03 |
4 | 电脑 | 华东 | 5000 | 2023-01-04 |
5 | 手机 | 华北 | 3000 | 2023-01-05 |
1. 按单个列分组
需求:按 region
(地区)分组,统计每个地区的总销售额(amount
总和)。
SELECT region, -- 分组列,必须出现在 GROUP BY 中SUM(amount) AS total_amount -- 聚合函数:计算每组的总销售额 FROM Sales GROUP BY region; -- 按地区分组
结果:
region | total_amount | |
---|---|---|
华北 | 11000 | (3000+5000+3000) |
华东 | 8000 | (3000+5000) |
2. 按多个列分组
需求:按 region
(地区)和 product
(产品)分组,统计每个地区每种产品的销售次数(订单数)和平均销售额。
SELECT region, product, -- 多列分组:先按地区分,同地区内再按产品分COUNT(order_id) AS order_count, -- 统计订单数AVG(amount) AS avg_amount -- 计算平均销售额 FROM Sales GROUP BY region, product -- 多列分组,顺序不影响结果(但建议按逻辑顺序) ORDER BY region, product; -- 按分组列排序
结果:
region | product | order_count | avg_amount | |
---|---|---|---|---|
华北 | 手机 | 2 | 3000 | (2 次订单,金额都是 3000) |
华北 | 电脑 | 1 | 5000 | (1 次订单) |
华东 | 手机 | 1 | 3000 | |
华东 | 电脑 | 1 | 5000 |
3. 用 HAVING
筛选分组结果
WHERE
用于分组前筛选行,HAVING
用于分组后筛选分组(只能跟在 GROUP BY
后,可使用聚合函数)。
需求:筛选出 “总销售额超过 8000” 的地区。
SELECT region,SUM(amount) AS total_amount FROM Sales GROUP BY region HAVING SUM(amount) > 8000; -- 分组后筛选:总销售额>8000
结果:
region | total_amount | |
---|---|---|
华北 | 11000 | (只有华北地区满足条件) |
4. 结合 WHERE
和 HAVING
需求:先筛选出 “2023 年 1 月 1 日后的销售记录”,再按地区分组,统计总销售额,并筛选出总销售额超过 5000 的地区。
SELECT region,SUM(amount) AS total_amount FROM Sales WHERE sale_date > '2023-01-01' -- 先筛选行:只保留1月1日后的记录 GROUP BY region HAVING SUM(amount) > 5000; -- 再筛选分组:总销售额>5000
结果:
region | total_amount | |
---|---|---|
华北 | 8000 | (1 月 2 日电脑 5000 + 1 月 5 日手机 3000) |
华东 | 8000 | (1 月 3 日手机 3000 + 1 月 4 日电脑 5000) |
三、常见聚合函数
分组查询中常用的聚合函数如下:
函数 | 作用 | 示例(基于上述 Sales 表) |
---|---|---|
COUNT() | 统计分组内的行数 | COUNT(*) 统计所有行;COUNT(amount) 统计非 NULL 的 amount 行数 |
SUM() | 计算列值总和(仅数值型) | SUM(amount) 计算总销售额 |
AVG() | 计算列值平均值(仅数值型) | AVG(amount) 计算平均销售额 |
MAX() | 取分组内列的最大值 | MAX(amount) 取每组最大销售额 |
MIN() | 取分组内列的最小值 | MIN(amount) 取每组最小销售额 |
四、注意事项
SELECT
与GROUP BY
的对应关系:SELECT
中所有非聚合函数的列必须出现在GROUP BY
中,否则会报错。例如:-- 错误示例:product 未在 GROUP BY 中,但出现在 SELECT 中(且非聚合) SELECT region, product, SUM(amount) FROM Sales GROUP BY region; -- 报错:product 不在 GROUP BY 中
WHERE
与HAVING
的区别:WHERE
:在分组前筛选行,不能使用聚合函数(如WHERE SUM(amount) > 1000
是错误的)。HAVING
:在分组后筛选分组,可以使用聚合函数(如HAVING SUM(amount) > 1000
是正确的)。
空值(NULL)的处理: 分组时,
NULL
会被视为 “相同值” 归为一组(即所有 NULL 行会被分到同一组)。性能优化: 对
GROUP BY
的列创建索引(如CREATE INDEX IX_Sales_Region ON Sales(region)
),可减少分组时的排序开销,提升性能。
总结
GROUP BY
是 SQL Server 中按类别汇总数据的核心工具,其核心流程是: 筛选行(WHERE
)→ 按列分组(GROUP BY
)→ 聚合计算 → 筛选分组(HAVING
)→ 排序(ORDER BY
)。 使用时需注意 SELECT
与 GROUP BY
的列对应关系,以及 WHERE
和 HAVING
的适用场景。