首页 > 数据库 > SQL > 正文

SQL分组查询的实现与优化:详解SQL中GROUP BY的用法

星夢妙者
发布: 2025-08-12 15:52:02
原创
482人浏览过

sql分组查询的核心是使用group by子句将数据按一个或多个列进行聚合,通常与聚合函数(如count、sum、avg等)结合使用,以实现分类汇总。1. group by在where之后执行,先过滤原始数据再分组;2. select中的非聚合列必须出现在group by中,否则会报错;3. having用于过滤分组后的聚合结果,而where用于分组前的行过滤;4. null值在group by中被视为独立的一组;5. 数据类型不一致可能导致分组异常;6. 性能优化可通过创建索引、减少数据量、避免在group by列上使用函数、利用覆盖索引等方式实现;7. rollup生成层次性汇总(如小计、总计);8. cube生成所有可能的分组组合(2^n种);9. grouping sets允许自定义多个分组集合,提升灵活性;10. 使用grouping()和grouping_id()函数可区分汇总行中的null与原始数据的null。掌握这些规则和技巧,能有效提升sql分组查询的准确性与性能。

SQL分组查询的实现与优化:详解SQL中GROUP BY的用法

SQL分组查询的核心在于将数据按一个或多个列进行聚合,而

GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
子句正是实现这一目标的关键。它允许我们对数据集进行分类汇总,比如计算每个部门的平均工资,或者统计每种产品的销售数量,从而从海量数据中提炼出有意义的洞察。简单来说,它就是让你能从“一堆散沙”里,看到“每一堆沙子的特点”。

解决方案

GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
子句的基本语法并不复杂,但其背后的逻辑和应用场景却非常丰富。它通常与聚合函数(如
COUNT()
登录后复制
,
SUM()
登录后复制
,
AVG()
登录后复制
,
MAX()
登录后复制
,
MIN()
登录后复制
)一起使用。当SQL引擎执行包含
GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
的查询时,它会先根据
FROM
登录后复制
登录后复制
登录后复制
WHERE
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
子句筛选出原始数据,然后按照
GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
指定的列对这些数据进行分组。每个分组被视为一个独立的单元,聚合函数会针对每个单元进行计算,最终返回每个组的聚合结果。

说实话,刚开始接触

GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
的时候,总觉得它有点抽象,毕竟不像
SELECT *
登录后复制
登录后复制
那么直观。但一旦你理解了它的“分组”逻辑,会发现它简直是数据分析的利器。它不是简单地把数据堆在一起,而是像一个分类器,把相似的东西归拢,然后对每个组进行独立计算。这种思维模式的转变,我觉得是掌握它的关键。

以下是一些常见的

GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
用法示例:

1. 基本分组与聚合: 统计每个部门的员工数量。

SELECT department, COUNT(employee_id) AS total_employees
FROM employees
GROUP BY department;
登录后复制

2. 多列分组: 按部门和职位统计平均工资。

SELECT department, position, AVG(salary) AS avg_salary
FROM employees
GROUP BY department, position;
登录后复制

3. 结合WHERE子句进行预过滤: 先筛选出工资大于5000的员工,再按部门统计人数。

SELECT department, COUNT(employee_id) AS high_salary_employees
FROM employees
WHERE salary > 5000
GROUP BY department;
登录后复制

需要注意的是,

WHERE
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
子句是在分组操作之前执行的,它用于过滤原始行。

4. 结合HAVING子句进行分组后过滤: 统计销售额超过10000的产品组。

SELECT product_id, SUM(sales_amount) AS total_sales
FROM sales
GROUP BY product_id
HAVING SUM(sales_amount) > 10000;
登录后复制

HAVING
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
子句则是在分组和聚合操作之后执行的,它用于过滤聚合结果。这是它与
WHERE
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
最核心的区别

为什么我的分组查询结果不对?常见误区与排查技巧

我记得有一次,写了个复杂的报表查询,结果出来一堆莫名其妙的数据。查了半天,才发现是

SELECT
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
里多了一个没放在
GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
里的字段。这种低级错误,谁都可能犯,但理解了背后的原理,下次就能避开。它就像是SQL在跟你较真:你既然要按A分组,那
SELECT
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
出来的非聚合字段,就必须是A本身,或者能从A推导出来的。

1. SELECT列表中的非聚合列未出现在GROUP BY中: 这是最常见的错误。SQL标准要求,在

SELECT
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
列表中,除了聚合函数的结果,所有非聚合列都必须出现在
GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
子句中。否则,数据库不知道如何为这些非聚合列选择一个值来代表整个组。

  • 错误示例:
    SELECT department, employee_name, COUNT(employee_id)
    FROM employees
    GROUP BY department;
    -- 错误:employee_name未在GROUP BY中
    登录后复制
  • 排查: 检查你的
    SELECT
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    列表,确保除了聚合函数外,所有列都已包含在
    GROUP BY
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    子句中。

2. WHERE与HAVING的混淆: 前面提到了,

WHERE
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
用于过滤原始行,
HAVING
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
用于过滤分组后的聚合结果。如果把本应由
HAVING
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
处理的条件放在
WHERE
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
里,或者反之,结果就会出错。

  • 错误示例:
    -- 意图:筛选平均工资大于5000的部门
    SELECT department, AVG(salary)
    FROM employees
    WHERE AVG(salary) > 5000 -- 错误:WHERE不能用聚合函数
    GROUP BY department;
    登录后复制
  • 排查: 记住顺序:
    FROM
    登录后复制
    登录后复制
    登录后复制
    ->
    WHERE
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    ->
    GROUP BY
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    ->
    HAVING
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    ->
    SELECT
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    。对原始行进行过滤用
    WHERE
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    ,对聚合结果进行过滤用
    HAVING
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制

3. NULL值的处理:

GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
操作中,
NULL
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
值会被视为一个单独的组。如果你不希望
NULL
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
值参与分组,需要在
WHERE
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
子句中明确排除它们。

  • 示例:
    -- 如果department列有NULL值,它们会形成一个单独的组
    SELECT department, COUNT(employee_id)
    FROM employees
    GROUP BY department;
    登录后复制
  • 排查: 考虑你的业务逻辑是否需要包含
    NULL
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    值的分组。

4. 数据类型不一致导致分组异常: 在某些数据库中,如果

GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
的列存在数据类型隐式转换,或者不同字符集、排序规则导致的值比较不一致,可能会导致分组结果不符合预期。

  • 排查: 检查涉及
    GROUP BY
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    的列的数据类型是否一致,必要时进行显式转换。

通用排查技巧:

  • 分步执行: 先只执行
    FROM
    登录后复制
    登录后复制
    登录后复制
    WHERE
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    ,看原始数据是否正确。
  • 逐步添加: 逐步添加
    GROUP BY
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    ,然后是聚合函数,最后是
    HAVING
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    。每一步都检查结果。
  • 简化查询: 如果查询很复杂,尝试将其简化为只包含
    GROUP BY
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    和一两个聚合函数的最基本形式,逐步增加复杂性。

如何优化大型数据集上的SQL分组查询性能?

优化SQL查询,特别是涉及到

GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
这种聚合操作时,常常让我觉得像是在玩一场智力游戏。你得想方设法让数据库少干活,或者干得更聪明。最直接的办法,当然是加索引。但索引也不是万能药,比如你在
GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
的字段上套个函数,那索引基本就废了。这种细节,往往是性能瓶颈的所在。

1. 索引优化:

GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
WHERE
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
子句中使用的列上创建合适的索引是提升性能的关键。索引可以加速数据扫描、排序和分组操作。对于多列分组,考虑创建复合索引,且索引列的顺序应与
GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
ORDER BY
登录后复制
的顺序一致,或者至少是前缀匹配。

  • 示例:

    -- 假设有一个大表 orders,经常需要按 customer_id 和 order_date 分组
    -- 创建复合索引可以加速查询
    CREATE INDEX idx_customer_order_date ON orders (customer_id, order_date);
    
    -- 查询示例,该索引有助于加速
    SELECT customer_id, COUNT(order_id)
    FROM orders
    WHERE order_date >= '2023-01-01'
    GROUP BY customer_id;
    登录后复制

    如果

    WHERE
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    子句的过滤性很好,且
    GROUP BY
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    的列也在索引中,数据库甚至可能直接通过索引完成排序和分组,避免全表扫描。

2. 减少数据量:

GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
操作发生之前,尽可能地减少需要处理的数据量。

  • WHERE子句前置过滤:
    GROUP BY
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    之前,使用
    WHERE
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    子句尽可能地过滤掉不需要的行。这能显著减少分组操作的数据量。
  • 选择性投影: 只在
    SELECT
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    列表中选择你真正需要的列,避免
    SELECT *
    登录后复制
    登录后复制
    ,减少网络传输和内存消耗。

3. 避免在GROUP BY列上使用函数: 如果在

GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
的列上使用了函数(如
YEAR(order_date)
登录后复制
),即使该列有索引,数据库也无法直接使用该索引进行分组优化,因为函数会改变列的原始值,导致索引失效。

  • 替代方案: 考虑创建函数索引(如果数据库支持)或在应用程序层处理,或将计算结果存储在单独的列中。

4. 利用覆盖索引: 如果一个索引包含了

SELECT
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
列表中的所有列(包括聚合函数依赖的列)以及
GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
WHERE
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
子句中使用的列,那么查询可以直接从索引中获取所有需要的数据,而无需回表(访问原始数据行),这会大大提高查询效率。

5. 调整数据库配置: 对于某些数据库系统(如MySQL),调整

sort_buffer_size
登录后复制
等参数可能会对
GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
操作(特别是当需要文件排序时)的性能产生影响。但这通常需要DBA的专业知识。

6. 分批处理或汇总表: 对于超大规模数据集,如果实时查询性能无法满足要求,可以考虑通过ETL(抽取、转换、加载)过程,将数据预先聚合到汇总表(或物化视图)中,后续查询直接针对汇总表进行,从而大幅提升查询速度。

GROUP BY的进阶用法:ROLLUP, CUBE, GROUPING SETS有什么用?

说实话,

ROLLUP
登录后复制
登录后复制
登录后复制
登录后复制
CUBE
登录后复制
登录后复制
登录后复制
登录后复制
GROUPING SETS
登录后复制
登录后复制
这些东西,刚开始听起来有点“高大上”,感觉离日常开发很远。但当你真的需要做一些复杂的报表,比如既要看每个月的销售额,又要看每年的总销售额,甚至还要看所有销售的总额时,它们简直是救星。手动写多个
UNION ALL
登录后复制
登录后复制
登录后复制
来实现这些汇总,那代码量和可读性简直是灾难。这几个关键字,就是为了解决这种多维度聚合的痛点而生的。

它们是SQL标准中提供的高级分组扩展,能够一次性生成多种维度的聚合结果,极大地简化了多维度分析的查询编写。

1. ROLLUP:生成分组总计和超级总计

ROLLUP
登录后复制
登录后复制
登录后复制
登录后复制
子句用于生成分组列的层次性汇总。它会在常规分组的基础上,从右到左依次移除
GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
列表中的列,并为这些子集生成聚合结果,最后还会生成一个总计(所有列都被移除)。

  • 示例:
    -- 按年份和月份统计销售额,并包含年度总计和所有年份的总计
    SELECT
        YEAR(order_date) AS order_year,
        MONTH(order_date) AS order_month,
        SUM(sales_amount) AS total_sales
    FROM sales
    GROUP BY ROLLUP(YEAR(order_date), MONTH(order_date));
    登录后复制

    结果会包含:(2023, 1), (2023, 2), ..., (2023, NULL) [2023年总计], (NULL, NULL) [所有年份总计]。

2. CUBE:生成所有可能的组合分组

CUBE
登录后复制
登录后复制
登录后复制
登录后复制
子句比
ROLLUP
登录后复制
登录后复制
登录后复制
登录后复制
更强大,它会生成
GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
列表中所有列的可能组合的聚合结果,包括所有单列分组、多列组合分组以及一个总计。如果
GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
中有N个列,
CUBE
登录后复制
登录后复制
登录后复制
登录后复制
会生成2^N种分组。

  • 示例:
    -- 统计产品类别和客户区域的所有组合销售额
    SELECT
        product_category,
        customer_region,
        SUM(sales_amount) AS total_sales
    FROM sales
    GROUP BY CUBE(product_category, customer_region);
    登录后复制

    结果会包含:(类别A, 区域X), (类别A, NULL) [类别A总计], (NULL, 区域X) [区域X总计], (NULL, NULL) [总计]等所有组合。

3. GROUPING SETS:自定义多个独立的GROUP BY子句

GROUPING SETS
登录后复制
登录后复制
允许你明确指定你想要生成的多个独立的分组集合。这提供了最大的灵活性,你可以合并多个
GROUP BY
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
查询的结果,而无需使用
UNION ALL
登录后复制
登录后复制
登录后复制

  • 示例:
    -- 既要按产品类别统计,又要按客户区域统计,同时还要一个总计
    SELECT
        product_category,
        customer_region,
        SUM(sales_amount) AS total_sales
    FROM sales
    GROUP BY GROUPING SETS(
        (product_category),     -- 按产品类别分组
        (customer_region),      -- 按客户区域分组
        ()                      -- 总计
    );
    登录后复制

    这等同于三个独立的

    GROUP BY
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    查询通过
    UNION ALL
    登录后复制
    登录后复制
    登录后复制
    连接起来,但效率更高。

4. GROUPING() 和 GROUPING_ID() 函数:识别汇总行 在使用

ROLLUP
登录后复制
登录后复制
登录后复制
登录后复制
CUBE
登录后复制
登录后复制
登录后复制
登录后复制
时,结果集中会出现
NULL
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
值,这些
NULL
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
可能表示原始数据中的
NULL
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
,也可能表示汇总行中的
NULL
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
(因为该维度被聚合了)。
GROUPING()
登录后复制
登录后复制
函数可以帮助区分这两种情况。它返回1表示该列是汇总生成的
NULL
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
,返回0表示是原始数据中的
NULL
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
GROUPING_ID()
登录后复制
则返回一个位图,表示所有分组列的汇总状态。

  • 示例:
    SELECT
        COALESCE(product_category, 'Total Category') AS product_category,
        COALESCE(customer_region, 'Total Region') AS customer_region,
        SUM(sales_amount) AS total_sales,
        GROUPING(product_category) AS is_category_total, -- 1表示product_category是汇总生成的NULL
        GROUPING(customer_region) AS is_region_total    -- 1表示customer_region是汇总生成的NULL
    FROM sales
    GROUP BY CUBE(product_category, customer_region);
    登录后复制

    通过

    GROUPING()
    登录后复制
    登录后复制
    函数,我们可以在应用程序中更准确地识别和处理这些汇总行。

以上就是SQL分组查询的实现与优化:详解SQL中GROUP BY的用法的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 //m.sbmmt.com/ All Rights Reserved | php.cn | 湘ICP备2023035733号