📜  MySQL汇总

📅  最后修改于: 2020-11-19 02:14:36             🧑  作者: Mango

MySQL汇总

MySQL中的ROLLUP是用于产生汇总输出的修饰符,包括表示超级汇总(较高级别)汇总操作的额外行。它使我们能够使用单个查询在多个分析级别上汇总输出。它主要用于为OLAP(在线分析处理)操作提供支持。

ROLLUP修饰符只能与MySQL中的GROUP BY查询一起使用。

句法:

以下是使用ROLLUP修饰符的语法:

SELECT 
    column1, column2, column3, ...
FROM 
    table_name
GROUP BY
    column1, column2,... WITH ROLLUP; 

使用这种语法,我们需要在SELECT子句中指定查询结果中显示的列名称。接下来,我们将提及表名称。之后,我们指定了GROUP BY子句,包括我们要基于其聚合数据的列名。最后,我们指定WITH ROLLUP修饰符以在另一行中获得超级聚合输出。

我们已经了解到,GROUP BY查询与诸如MAX,MIN,SUM,COUNT,AVG等聚合函数一起应用,这些函数按单列或多列对输出行进行分组。 ROLLUP修饰符是使用GROUP BY查询的选项,该查询包含用于表示小计的额外字段。这些额外的行称为超级汇总行,是总计行的总和。因此,ROLLUP修饰符使我们可以基于MySQL中GROUP BY子句中指定的列,在单个查询中创建一组集合行。

MySQL ROLLUP解释

如果我们想了解ROLLUP修饰符,则必须知道什么是分组集。分组集是我们要分组以获取结果输出的一组列的集合。例如,假设我们有一个包含以下数据的“ sales”表:

如果我们想总结每年的结果,我们将使用简单的GROUP BY子句,如下所示:

SELECT Year, SUM(Sale) AS Total_Sales 
FROM sales 
GROUP BY Year;

它将给出以下输出,显示每年的总销售额(总计):

在上面的查询中,分组集由列名Year表示。如果需要在单个查询中一起生成多个分组集,则可以如下使用UNION ALL运算符:

SELECT Year, SUM(Sale) AS Total_Sales 
FROM sales 
GROUP BY Year
UNION ALL
SELECT NULL, SUM(Sale) AS Total_Sales 
FROM sales;

在此查询中,我们可以看到NULL列。这是因为UNION ALL子句要求所有查询具有相同数量的列。因此,为了满足此要求,我们在第二个查询的选择列表中添加了NULL。

执行查询时,将得到以下输出:

Year列的输出中的NULL表示超级总计的总计值。由于此查询能够生成每年的总销售额以及总销售额的总和,因此,它有两个问题:

  • 它使查询相当冗长。
  • 因为数据库引擎在内部执行两个单独的查询并将结果集组合为单个输出,所以它降低了查询的性能。

为了解决这些问题,MySQL允许我们使用ROLLUP子句,该子句在一个查询中提供了两种分析级别。 ROLLUP子句是GROUP BY子句的扩展,该子句产生另一行并显示总计(超级聚集)值。

让我们在向组BY子句添加WITH ROLLUP修饰符后显示结果,该修饰符显示所有年份的总计值:

SELECT Year, SUM(Sale) AS Total_Sales 
FROM sales 
GROUP BY Year WITH ROLLUP;

当我们执行命令时,我们将得到如下输出:

在此输出中,我们可以在Year列中看到NULL值,该值标识了超汇总行。它清楚地表明,ROLLUP子句不仅生成小计,而且还给出了全年总销售额的总计。

如果GROUP BY子句具有多个列,则ROLLUP修饰符的作用更为复杂。在这种情况下,ROLLUP修饰符假定GROUP BY子句中指定的列之间的层次结构。每次列值发生变化时,查询都会在结果末尾生成一个额外的超级汇总汇总行。

例如,假设我们在GROUP BY子句中指定了三列,如下所示:

GROUP BY c1, c2, c3 WITH ROLLUP

ROLLUP修饰符采用以下层次结构:

c1 > c2 > c3

并生成以下分组集:

(c1, c2, c3)
(c1, c2)
(c1)
()

请参阅下面的查询以更清楚地解释它:

SELECT Year, Country, Product, SUM(Sale) AS Total_Sales
FROM sales
GROUP BY Year, Country, Product;

如果没有ROLLUP,则基于GROUP BY子句中指定的多个列的sales表的摘要类似于以下输出。在这里,我们将仅在年份/国家/产品分析级别获得汇总值。

添加ROLLUP后,查询会产生一些额外的行:

SELECT Year, Country, Product, SUM(Sale) AS Total_Sales
FROM sales
GROUP BY Year, Country, Product WITH ROLLUP;

请参见以下输出:

上面的输出生成了四个分析级别的信息,下面对此进行了说明:

  • 首先,给定年份和国家/地区的每组产品行都会生成一个额外的超级汇总摘要行,该行显示所有产品的总数。它将product列设置为NULL。
  • 接下来,给定年份的每组行都会生成一个额外的超级汇总摘要行,该行显示所有国家和产品的总计。它将“国家和地区”和“产品”列设置为NULL。
  • 最后,对于所有其他行,它会生成一个额外的超级聚合摘要行,该行显示所有列的总计。它将Year,Country和Products列设置为NULL。

如果我们更改GROUP BY列中指定的列顺序,则会得到不同的结果:

SELECT Year, Country, Product, SUM(Sale) AS Total_Sales
FROM sales
GROUP BY Country, Year, Product WITH ROLLUP;

请参阅以下输出:

GROUPING()函数

GROUPING()函数用于检查结果集中的NULL是否表示常规分组值,超聚合值或总计。当超级汇总行中出现NULL时,它返回1。否则,它返回0。

我们可以在选择列表,HAVING子句和ORDER BY子句中使用GROUPING()函数。

请参阅以下查询:

SELECT Year, Country, Product, SUM(Sale) AS Total_Sales,
         GROUPING(Year),
         GROUPING(Country),
         GROUPING(Product)
       FROM sales
       GROUP BY Year, Country, Product WITH ROLLUP; 

当超级汇总行中Year列中的NULL出现时,GROUPING(Year)返回1,我们将得到以下输出。否则,它将返回零。

同样,当“国家/地区”列中的NULL在超级聚合行中出现时,GROUPING(Country)返回1。否则,它将返回零。

另外,当在超聚合行中的Product列中为NULL时,GROUPING(Product)返回1。否则,它将返回零。

我们还可以使用GROUPING()函数将有意义的标签替换为超聚合NULL值,而不是直接显示它。

以下查询说明了如何将IF()函数与GROUPING()函数结合起来,以用标签替换Year,Country和Product列中的超级聚合NULL值:

SELECT
         IF(GROUPING(Year), 'All years', year) AS year,
         IF(GROUPING(Country), 'All countries', country) AS country,
         IF(GROUPING(Product), 'All products', product) AS product,
         SUM(Sale) AS Total_Sales
       FROM sales
       GROUP BY Year, Country, Product WITH ROLLUP;

我们将得到如下输出:

如果在GROUPING()函数有多个参数,它将返回代表位掩码的输出,该掩码合并了每个表达式的结果。在这里,最低位产生最右边参数的结果。下面的示例将像这样评估:

示例:分组(年份,国家/地区,产品)

  result for GROUPING(Product)
+ result for GROUPING(Country) << 1
+ result for GROUPING(Year) << 2

如果任何参数具有超聚合NULL值,则此GROUPING()的结果将为非零。在这种情况下,它将仅返回超级聚集的行,并使用以下查询过滤常规的分组行:

mysql> SELECT Year, Country, Product, SUM(Sale) AS Total_Sale
       FROM sales
       GROUP BY Year, Country, Product WITH ROLLUP
       HAVING GROUPING(Year, Country, Product) <> 0;

它将给出以下输出: