转自:[https://www.yiibai.com/sql/sql-rollup.html](https://www.yiibai.com/sql/sql-rollup.html)
# 1. SQL ROLLUP简介
`ROLLUP`是`GROUP BY`子句的扩展。 `ROLLUP`选项允许包含表示小计的额外行,通常称为超级聚合行,以及总计行。 通过使用`ROLLUP`选项,可以使用单个查询生成多个分组集。
> 注意,分组集是一组用于分组的列。 例如,一个由仓库返回库存的查询,分组集是(`warehouse`)。
```sql
SELECT
warehouse,
SUM(quantity) qty
FROM
inventory
GROUP BY
warehouse;
```
有关`GROUPING SETS`的更多信息,请查看分组集教程。
以下是SQL `ROLLUP`的基本语法:
```sql
SELECT
c1, c2, aggregate_function(c3)
FROM
table
GROUP BY ROLLUP (c1, c2);
```
`ROLLUP`假定输入列之间存在层次结构。 例如,如果输入列是`(c1,c2)`,则层次结构`c1 > c2`。 `ROLLUP`生成考虑此层次结构有意义的所有分组集。 这就是为什么我们经常使用`ROLLUP`来生成小计和总计以用于报告目的。
在上面的语法中,`ROLLUP(c1,c2)`生成以下三个分组集:
* (c1,c2)
* (c1)
* ()
Oracle,Microsoft SQL Server和PostgreSQL支持此语法。 但是,MySQL的语法略有不同,如下所示:
```sql
SELECT
c1, c2, aggregate_function(c3)
FROM
table_name
GROUP BY c1, c2 WITH ROLLUP;
```
# 2. SQL ROLLUP示例
我们将使用在[GROUPING SETS教程](GROUPING SETS用法)中设置的`inventory`表进行演示。
```sql
mysql> select * from inventory;
+---------------+---------+----------+----------+
| warehouse | product | model | quantity |
+---------------+---------+----------+----------+
| San Jose | iPhone | 6s | 100 |
| San Fransisco | iPhone | 6s | 50 |
| San Jose | iPhone | 7 | 50 |
| San Fransisco | iPhone | 7 | 10 |
| San Jose | iPhone | X | 150 |
| San Fransisco | iPhone | X | 200 |
| San Jose | Samsung | Galaxy S | 200 |
| San Fransisco | Samsung | Galaxy S | 200 |
| San Fransisco | Samsung | Note 8 | 100 |
| San Jose | Samsung | Note 8 | 150 |
+---------------+---------+----------+----------+
10 rows in set
```
## 2.1. SQL ROLLUP有一个列示例
以下语句使用`GROUP BY`子句和`SUM()`函数按仓库查找总库存:
```sql
SELECT
warehouse, SUM(quantity)
FROM
inventory
GROUP BY warehouse;
+---------------+---------------+
| warehouse | SUM(quantity) |
+---------------+---------------+
| San Fransisco | 560 |
| San Jose | 650 |
+---------------+---------------+
2 rows in set
```
要检索所有仓库中的总产品数,请将`ROLLUP`添加到`GROUP BY`子句,如下所示:
```sql
SELECT
warehouse, SUM(quantity)
FROM
inventory
GROUP BY ROLLUP(warehouse);
```
执行上面示例代码,得到以下结果:
```
warehouse | sum
---------------+------
null | 1210
San Fransisco | 560
San Jose | 650
```
正如在结果中看到的那样,`warehouse`列中的`NULL`值指定了总计超级聚合行。 在此示例中,`ROLLUP`选项使查询生成另一行,显示所有仓库中的总产品数量。
要使输出更具可读性,可以使用`COALESCE()`函数将`NULL`值替换`All`值,如下所示:
```sql
SELECT
COALESCE(warehouse, 'All warehouses') AS warehouse,
SUM(quantity)
FROM
inventory
GROUP BY ROLLUP (warehouse);
```
执行上面示例代码,得到以下结果:
```
warehouse | sum
----------------+------
All warehouses | 1210
San Fransisco | 560
San Jose | 650
```
## 2.2. SQL ROLLUP有多列示例
以下语句按`warehouse`和`product`计算库存:
```sql
SELECT
warehouse, product, SUM(quantity)
FROM
inventory
GROUP BY warehouse, product;
```
执行上面示例代码,得到以下结果:
```
warehouse | product | sum
---------------+---------+-----
San Fransisco | iPhone | 260
San Fransisco | Samsung | 300
San Jose | iPhone | 300
San Jose | Samsung | 350
```
将`ROLLUP`添加到`GROUP BY`子句:
```sql
SELECT
warehouse, product, SUM(quantity)
FROM
inventory
GROUP BY ROLLUP (warehouse , product);
```
执行上面示例代码,得到以下结果:
```
warehouse | product | sum
---------------+---------+------
null | null | 1210 -- 总计
San Fransisco | iPhone | 260
San Fransisco | Samsung | 300
San Jose | iPhone | 300
San Jose | Samsung | 350
San Fransisco | null | 560 -- San Fransisco仓库的小计
San Jose | null | 650 -- San Jose仓库的小计
```
请注意,输出包含两个分析级别的摘要信息,而不仅仅是一个:
* 在指定仓库的每组产品行之后,将显示一个额外的摘要行,显示总库存。 在这些行中,`product`列中的值设置为`NULL`。
* 在所有行之后,将显示一个额外的摘要行,显示所有仓库和产品的总库存。 在这些行中,`warehouse` 和 `product` 列中的值设置为`NULL`。
## 2.3. SQL ROLLUP带有部分汇总的示例
可以使用`ROLLUP`执行部分汇总,以减少计算的小计数,如以下示例所示:
```sql
SELECT
warehouse, product, SUM(quantity)
FROM
inventory
GROUP BY warehouse, ROLLUP (product);
```
执行上面示例代码,得到以下结果:
```
warehouse | product | sum
---------------+---------+-----
San Fransisco | iPhone | 260
San Fransisco | Samsung | 300
San Jose | iPhone | 300
San Jose | Samsung | 350
San Fransisco | null | 560
San Jose | null | 650
```
在此示例中,`ROLLUP`仅为`product`列而不是`warehouse`列生成超级聚合摘要。