首页 > 数据库 >PostgreSQL 分组汇总(二)

PostgreSQL 分组汇总(二)

时间:2023-07-15 15:55:44浏览次数:34  
标签:PostgreSQL 汇总 sales item 分组 year quantity GROUPING

PostgreSQL除了支持基本的GROUP BY分组操作之外,还支持3种高级的分组选项:GROUPING SETS、ROLLUP以及CUBE。

GROUPING SETS选项

GROUPING SETS是GROUP BY的扩展选项,用于指定自定义的分组集。举例来说,以下是一个销售数据表:

CREATE TABLE sales
(
    item     VARCHAR(10),
    year     VARCHAR(4),
    quantity INT
);
INSERT INTO sales
VALUES ('apple', '2018', 800);
INSERT INTO sales
VALUES ('apple', '2018', 1000);
INSERT INTO sales
VALUES ('banana', '2018', 500);
INSERT INTO sales
VALUES ('banana', '2018', 600);
INSERT INTO sales
VALUES ('apple', '2019', 1200);
INSERT INTO sales
VALUES ('banana', '2019', 1800);
select * from sales;

按照产品(item)和年度(year)进行分组汇总时,所有可能的4种分组集包括:

  • 按照产品和年度的组合进行分组;
  • 按照产品进行分组;
  • 按照年度进行分组;
  • 所有数据分为一组;

可以通过以下多个查询获取所有分组集的分组结果:

--按照产品和年度的组合进行分组
SELECT item, year, SUM(quantity) sum_quantity
FROM sales
GROUP BY item, year
union all
--按照产品进行分组
SELECT item, null as year, SUM(quantity) sum_quantity
FROM sales
GROUP BY item
union all
--按照年度进行分组
SELECT null as item, year, SUM(quantity) sum_quantity
FROM sales
GROUP BY year
union all
--所有数据分为一组
SELECT null as item, null as year, SUM(quantity) sum_quantity
FROM sales;

这种方法存在一些问题:首先,查询语句比较冗长,查询的次数随着分组字段的增加呈指数增长;其次,多次查询意味着需要多次扫描同一张表,存在性能上的问题。GROUPING SETS是GROUP BY的扩展选项,能够为这种查询需求提供更加简单有效的解决方法。我们使用分组集改写上面的示例:
SELECT item, year, SUM(quantity) sum_quantity
FROM sales
GROUP BY grouping sets ((item,year),(item),(year),());

GROUPING SETS选项用于定义分组集,每个分组集都需要包含在单独的括号中,空白的括号(())表示将所有数据当作一个组处理。查询的结果等于前文4个查询的合并结果,但是语句更少,可读性更强;而且PostgreSQL执行时只需要扫描一次销售表,性能更加优化。另外,默认的GROUP BY使用由所有分组字段构成的一个分组集,本示例中为((item, year))。

CUBE选项

随着分组字段的增加,即使通过GROUPING SETS列出所有可能的分组方式也会显得比较麻烦。设想一下使用4个字段进行分组统计的场景,所有可能的分组集共计有16个。这种情况下编写查询语句仍然很复杂,为此PostgreSQL提供了简写形式的GROUPING SETS:CUBE和ROLLUP。CUBE表示所有可能的分组集,例如:

CUBE ( c1, c2, c3 )

等价于:

GROUPING SETS (( c1, c2, c3 ),( c1, c2 ),( c1, c3 ),( c2, c3 ),( c1),( c2 ),( c3 ),( ))

因此,可以进一步将上面的示例改写如下:

SELECT item, year, SUM(quantity) sum_quantity
FROM sales
GROUP BY cube (item, year);

ROLLUP选项

GROUPING SETS第二种简写形式就是ROLLUP,用于生成按照层级进行汇总的结果,类似于财务报表中的小计、合计和总计。例如:

ROLLUP ( c1, c2, c3 )

等价于:

GROUPING SETS (( c1, c2, c3 ),( e1, e2 ),( e1 ),( ))

以下查询返回按照产品和年度组合进行统计的销量小计,加上按照产品进行统计的销量合计,再加上所有销量的总计:

SELECT item, year, SUM(quantity) sum_quantity
FROM sales
GROUP BY rollup (item, year);

查看结果时,需要根据每个字段上的空值进行判断。比如第一行的产品和年度都为空,因此它是所有销量的总计。为了便于查看,可以将空值进行转换显示:

SELECT coalesce(item, '所有产品') ·产品·,
       coalesce(year, '所有年度') 年度,
       SUM(quantity)          销量
FROM sales
GROUP BY rollup (item, year);

COALESCE函数返回第一个非空的参数值。可以根据需要返回按照某些组合进行统计的结果,以下查询返回按照产品和年度组合进行统计的销量小计,加上按照产品进行统计的销量合计:

SELECT coalesce(item, '所有产品') ·产品·,
       coalesce(year, '所有年度') 年度,
       SUM(quantity)          销量
FROM sales
GROUP BY item, rollup (year);

对于CUBE和ROLLUP而言,每个元素可以是单独的字段或表达式,也可以是使用括号包含的列表。如果是括号中的列表,产生分组集时它们必须作为一个整体。例如:

CUBE ( (c1, c2), (c3, c4) )

等价于:

GROUPING SETS (( c1, c2, c3, c4 ),( c1, c2 ),( c3, c4 ),( ))

因为c1和c2是一个整体,c3和c4是一个整体。同样:

ROLLUP ( c1, (c2, c3), c4 )

等价于:

GROUPING SETS (( c1, c2, c3, c4 ),( c1, c2, c3 ),( c1 ),( ))

GROUPING函数

虽然有时候可以通过空值来判断数据是不是某个字段上的汇总,比如说按照年度进行统计的结果在字段year上的值为空。但是情况并非总是如此,考虑以下示例:

--未知产品在2018 年的销量为5000
INSERT INTO sales
VALUES (NULL, '2018', 5000);
SELECT coalesce(item, '所有产品') AS "产品", coalesce(year, '所有年度') AS "年度", SUM(quantity) AS "销量"
FROM sales
GROUP BY ROLLUP (item, year);

其中第5行和第7行的显示存在问题,它们分别应该是未知产品在2018年的销量小计和所有年度的销量合计。问题的关键在于无法区分是分组产生的NULL还是源数据中的NULL。为了解决这个问题,PostgreSQL提供了一个分组函数:GROUPING。

以下查询显示了GROUPING函数的结果:

select item          产品,
       year          年度,
       sum(quantity) 销量,
       grouping(item),
       grouping(year),
       grouping(item, year)
from sales
group by rollup (item, year);

GROUPING函数如果只有一个参数,返回整数0或者1。如果某个统计结果使用的分组集包含了函数中的参数字段,该函数返回0,否则返回1。比如说,第1行数据是所有产品所有年度的统计(分组集为空),所以GROUPING(item)和GROUPING(year)结果都是1;第7行数据是未知产品所有年度的统计(分组集为(item, )),所以GROUPING(item)结果为0,GROUPING(year)结果为1。GROUPING函数如果包含多个参数,针对每个参数返回整数0或者1,然后将它们按照二进制数值连接到一起。比如说,第1行数据中的GROUPING(item, year)结果等于GROUPING(item)和GROUPING(year)结果的二进制数值连接,也就是3(二进制的11)。通过使用GROUPING函数,我们可以正确显示分组中的NULL值和源数据中的NULL值:

select case when grouping(item) = 1 then '所有产品' else item end 产品,
       case when grouping(year) = 1 then '所有年度' else year end 年度,
       sum(quantity)                                          销量
from sales
group by rollup (item, year);

标签:PostgreSQL,汇总,sales,item,分组,year,quantity,GROUPING
From: https://www.cnblogs.com/wdh01/p/17233549.html

相关文章

  • 常用adb命令汇总
    一、adb介绍adb:AndroidDebugBridge,Android调试桥的缩写,adb是一个C/S架构的命令行工具,主要由3部分组成:运行在PC端的Client:可以通过它对Android应用进行安装、卸载及调试运行在PC端的Service:其管理客户端到Android设备上adb后台进程的连接运行在A......
  • PostgreSQL技术大讲堂 - 第22讲:CLOG作用与管理
     PostgreSQL从小白到专家,是从入门逐渐能力提升的一个系列教程,内容包括对PG基础的认知、包括安装使用、包括角色权限、包括维护管理、、等内容,希望对热爱PG、学习PG的同学们有帮助,欢迎持续关注CUUGPG技术大讲堂。第22讲:CLOG作用与管理内容1:PostgreSQLCLOG概述内容2:CLOG......
  • 【AGC】云数据库开发常见问题汇总
    ​ 【问题背景】近期越来越多的开发者通过SDK使用云数据库,云数据库是一款支持端云数据协同管理、可扩展的Serverless数据库产品,提供简单易用的多平台原生SDK,您的应用可以通过SDK直接访问云侧数据库。同时,云数据库还支持通过ServerSDK直接管理云侧数据,实现云侧数据的高效管理。......
  • PostgreSQL 分组汇总(一)
    聚合函数聚合函数(aggregatefunction)针对一组数据行进行运算,并且返回单个结果。PostgreSQL支持以下常见的聚合函数:AVG-计算一组值的平均值。COUNT-统计一组值的数量。MAX-计算一组值的最大值。MIN-计算一组值的最小值。SUM-计算一组值的和值。STRING_AGG-连接一组字符串。......
  • postgresql 简单使用
    编译安装的启动数据库:/usr/local/postgresql/bin/pg_ctl-D/data/postgresql-llogfilestart停止数据库:/usr/local/postgresql/bin/pg_ctl-D/data/postgresqlstop-mfast登录数据库:/usr/local/postgresql/bin/psqlpostgres 配置文件:/data/postgresql/postgresql.con......
  • 【FAQ】API6低代码开发问题汇总
    ​参考文档:低代码开发参考文档:https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ide-low-code-0000001158284713基于景区模板开发元服务:https://developer.huawei.com/consumer/cn/doc/distribution/app/agc-lowcode-templateoverview-0000001548015654 ......
  • 我遇到的hadoop错误和解决方法汇总
     ==================================windowscygwin环境下,遇到这个错误:org.apache.hadoop.security.AccessControlException:Permissiondenied:user=cyg_server,access=EXECUTE,inode="job_201010161322_0003":heipark:supergroup:rwx------ 解决:刚开始还使用“./bin/hadoo......
  • PostgreSQL 限定结果数量
    查询语句的结果可能包含成百上千行数据,但是前端显示时也许只需要其中的小部分,例如TOP-N排行榜;或者为了便于查看,每次只显示一定数量的结果,例如分页功能。为了处理这类应用,SQL提供了标准的FETCH和OFFSET子句。另外,PostgreSQL还实现了扩展的LIMIT语法。Top-N查询这类查询通常是为了......
  • Postgresql统计所有表的基本信息(如行数、大小等)
    pg_class目录pg_class记录表和几乎所有具有列或者像表的东西。这包括索引(但还要参见pg_index)、序列、视图、物化视图、组合类型和TOAST表。pg_class中的一些逻辑标志被以一种懒惰的方式维护:在正确状态时它们被保证为真,但是当条件不再为真时它们并不会被立刻重置为假。例如......
  • PHP 生成数据库的 markdown 字段说明文档,支持 mysql,postgresql
    安装composerrequirepeng49/db2markdown命令行使用phpvendor/bin/db2markdown输入数据库的地址(host),端口(port)用户名,密码,要导出的表,默认是*,生成所有表的文档,指定多个表明用逗号隔开,如:table1,table2$phpsrc/bin/db2markdownpleaseenterthedb(1mys......