postgresql高级应用之行转列&汇总求和的实现思路

前言

节前公司业务方需要做一個統計報表,这个报表用于统计当月估计几个明星品的销售情况,而我们的数据是按行存储的就是日期|产品|渠道|销售额这样,说是也奇了怪了,我们买的报(guan)表(yuan)系(la)统(ji) 竟然不能容易地实现。。。,于是我看了看,然后想了想,发现是可以通过sql算出这样一个报表(多亏了postgresql的高阶函数😂),然后直接将数据输出到报表系统 完事兒~ ,以下 我將sql關鍵部分描述下,至於對前端展示有興趣的同學可留言,可考慮作一節講講哈😄~

报表

首先,業務需要的報表長這樣子的,看起來似乎還OK哈~

接下來我先給出我的測試脚本(均測試&無bug)~

表结构

drop table if EXISTS  report1 ;
CREATE TABLE "report1" (
  "id" numeric(22) NOT NULL,
  "date" date NOT NULL,
  "product" varchar(100),
  "channel" varchar(100),
  "amount" numeric(20,4)
);

表注释

字段 描述
id 主键
date 日期
product 产品
channel 渠道
amount 销售额

表数据

INSERT INTO "report1"("id", "date", "product", "channel", "amount") VALUES ('2105051726328010100000', '2021-05-04', '产品1', '京东', '8899.0000');
INSERT INTO "report1"("id", "date", "product", "channel", "amount") VALUES ('2105051726328010100001', '2021-05-04', '产品2', '京东', '99.0000');
INSERT INTO "report1"("id", "date", "product", "channel", "amount") VALUES ('2105051727068010100010', '2021-05-04', '产品1', '天猫', '230.0000');
INSERT INTO "report1"("id", "date", "product", "channel", "amount") VALUES ('2105051727068010100011', '2021-05-04', '产品2', '天猫', '9.9000');
INSERT INTO "report1"("id", "date", "product", "channel", "amount") VALUES ('2105051727068010100011', '2021-05-04', '产品3', '线下门店', '10.1000');
INSERT INTO "report1"("id", "date", "product", "channel", "amount") VALUES ('2105051727068010100000', '2021-05-04', '产品1', '其它', '10');
INSERT INTO "report1"("id", "date", "product", "channel", "amount") VALUES ('2105051727068010100099', '2021-05-04', '产品2', '其它', '20000');
INSERT INTO "report1"("id", "date", "product", "channel", "amount") VALUES ('2105051727068010100033', '2021-05-01', '产品1', '其它', '20000');
INSERT INTO "report1"("id", "date", "product", "channel", "amount") VALUES ('2105051727068010100044', '2021-05-01', '产品3', '线下门店', '12345');

思考

如果你看到這裏請稍稍思考下,一開篇我説過我們的數據是按 日期|产品|渠道|销售额 這樣按行存儲的,以上截圖大家一看就懂,然後再看看開篇的報表截圖,我想大家可以同我一樣可以分析出以下幾點:

  • 報表縱向看大致分三部分

一部分是前一日產品銷售明細
然後一部分是前一日產品渠道產品合計
最後一部分是按渠道做的月統計

  • 報表橫向看大致分兩部分

一部分是前一日的數據
另一部分則是月份匯總數據

最後一部分則是所有渠道的產品合計、日合計、月合計

好了,問題來了,如何做呢,我是這麽想的:首先要很清楚的是你的sql大致分兩大部分(兩個子查詢)

一部分是前一日的數據另一部分則是月份匯總數據

最後需要將兩部分數據做聯表查詢,這樣太贊了,似乎完成了報表的80%,至於最後一行的求總,這裏先賣個關子哈~

第一部分數據(前一日的數據)

我想我們立馬能做的第一部分sql恐怕就是行專列吧(似乎這是最容易實現的😄)

select
  channel,
  sum(case product when '产品1' then amount end) as c1,
  sum(case product when '产品2' then amount end) as c2,
  sum(case product when '产品3' then amount end) as c3
from report1
group by channel ;

sql似乎沒什麽問題,但是我們少了一列,對那就是按渠道日合計,當然如果您對postgresql窗口函數熟悉的話,這裏實現的方式估計你已經猜到了(窗口over函數),上sql...

select
  channel,
  day_sum,
  sum(case product when '产品1' then amount end) as c1,
  sum(case product when '产品2' then amount end) as c2,
  sum(case product when '产品3' then amount end) as c3
from
  ( select *,sum(amount) over (partition by channel) as day_sum from report1  where date=to_date('2021-05-04','yyyy-MM-dd') ) as t1
group by t1.channel ,t1.day_sum;

哈哈,上圖的day_sum估計大家很熟悉了吧,哈哈哈~
看來已經成功地完成了日數據部分,這裏可能的難點可能就兩點

  • 一是使用聚合函數(sum)+分組(group by)做行專列(當然postgresql也有其他很好用的行專列擴展,這裏就不介紹啦~)另一個是使用窗口函數(over)對明細提前做 按渠道的窗口匯總,這樣渠道日合計(行)的數據就有啦~

想想是不是很容易😂,接下來我們看看第二部分數據怎麽獲取~

第二部分數據(月份匯總數據)

月份匯總的數據看似簡單的可怕,如果您熟練掌握postgresql中的日期處理的話估計分分鐘就能搞定,這裏就不耍大刀了,直接放出sql,哈哈哈😄

select
  channel,sum(amount) as month_sum from report1
where
  date>=date(date_trunc('month',to_date('2021-05-04','yyyy-MM-dd'))) and date < date(date_trunc('month',to_date('2021-05-04','yyyy-MM-dd')) + '1 month')
group by
  channel

報表數據最終求解

現在,我們將求解的兩部分數據按渠道channel字段做inner join合并以上兩部分數據,合并后的數據大致是這樣子的

這個是sql

select
    ttt.channel,
    sum(ttt.day_sum) as day_sum,
    sum(ttt.month_sum) as month_sum,
    sum(ttt.c1) as c1,
    sum(ttt.c2) as c2,
    sum(ttt.c3) as c3
from (
        select tt1.*,tt2.month_sum from
        (
        select
        channel,
      day_sum,
        sum(case product when '产品1' then amount end) as c1,
        sum(case product when '产品2' then amount end) as c2,
        sum(case product when '产品3' then amount end) as c3
        from
        ( select *,sum(amount) over (partition by channel) as day_sum from report1  where date=to_date('2021-05-04','yyyy-MM-dd') ) as t1
        group by t1.channel ,t1.day_sum
        ) as tt1 left join
        (
          select channel,sum(amount) as month_sum from report1 where date>=date(date_trunc('month',to_date('2021-05-04','yyyy-MM-dd'))) and date < date(date_trunc('month',to_date('2021-05-04','yyyy-MM-dd')) + '1 month') group by  channel
        ) as tt2 on tt1.channel = tt2.channel
    ) ttt
GROUP BY ttt.channel
order by channel asc

看,匯總的數據已經有了,已經可以算作是最終結果了(如果你需要報表系統來計算匯總行數據的話),當然 ,我們的報表系統過於繁瑣(不是不能做,而是太麻煩),需要你將做好的菜喂給它吃,這時,該怎麽辦呢。。。,哈哈哈 我們似乎忘記了很久不用的rollup函數(一開始我也沒發現有這麽個函數哈哈),試試看吧

select
    ttt.channel,
    sum(ttt.day_sum) as day_sum,
    sum(ttt.month_sum) as month_sum,
    sum(ttt.c1) as c1,
    sum(ttt.c2) as c2,
    sum(ttt.c3) as c3
    from (
        select tt1.*,tt2.month_sum from
        (
        select
        channel,
      day_sum,
        sum(case product when '产品1' then amount end) as c1,
        sum(case product when '产品2' then amount end) as c2,
        sum(case product when '产品3' then amount end) as c3
        from
        ( select *,sum(amount) over (partition by channel) as day_sum from report1  where date=to_date('2021-05-04','yyyy-MM-dd') ) as t1
        group by t1.channel ,t1.day_sum
        ) as tt1 left join
        (
          select channel,sum(amount) as month_sum from report1 where date>=date(date_trunc('month',to_date('2021-05-04','yyyy-MM-dd'))) and date < date(date_trunc('month',to_date('2021-05-04','yyyy-MM-dd')) + '1 month') group by  channel
        ) as tt2 on tt1.channel = tt2.channel
    ) ttt
    group by rollup(ttt.channel)
    order by channel asc

數是對的,意味著我們成功了~😂

總結

如果您肯下功夫學,postgresql世界有很多精彩的東西,當然也有一些東西對比mysql顯得繁瑣些,不過本著學習的心態,我們縂能剋服這些,同時我們還是能做出超出我們自身能力範疇的東西的,哈哈,各位加油哦~

下章,我將講一講如何實現通過sql實現前端合并單元格的效果,是不是很神奇(我保證你全網搜不到), 希望不翻車,哈哈哈~

到此这篇关于postgresql高级应用之行转列&汇总求和的实现思路的文章就介绍到这了,更多相关postgresql行转列汇总求和内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • PostgreSQL 实现将多行合并转为列

    需求将下列表格相同id的name拼接起来输出成一列 id Name 1 peter 1 lily 2 john 转化后效果: id Name 1 peter:lily 2 john: 实现方式使用 array_to_string 和 array_agg 函数,具体语句如下: string_agg(expression, delimiter) 把表达式变成一个数组 string_agg(expression, delimiter) 直接把一个表达式变成字符串 select id, array_to

  • PostgreSQL实现交叉表(行列转换)的5种方法示例

    交叉表 交叉表(Cross Tabulations)是一种常用的分类汇总表格.使用交叉表查询,显示源于表中某个字段的汇总值,并将它们分组,其中一组列在数据表的左侧,另一组列在数据表的上部.行和列的交叉处可以对数据进行多种汇总计算,如:求和.平均值.记数.最大值.最小值等.使用交叉表查询数据非常直观明了,被广泛应用.交叉表查询也是数据库的一个特点. 例如: select 表1.组名, (select 表1.成员姓名 from 表2 b where 表1.成员1id=表2.成员id) as 成员1i

  • PostgreSQL 实现列转行问题

    1 测试表数据 SELECT relative_label_content FROM frk_s.label_cor_gene relative_label_content ------ AA BB CC 2 列转行写法 写法1: string_agg SELECT frwybs, string_agg (relative_label_content, ',') as relative_label_content FROM frk_s.label_cor_gene GROUP BY frwybs

  • postgresql高级应用之行转列&汇总求和的实现思路

    前言 节前公司业务方需要做一個統計報表,这个报表用于统计当月估计几个明星品的销售情况,而我们的数据是按行存储的就是日期|产品|渠道|销售额这样,说是也奇了怪了,我们买的报(guan)表(yuan)系(la)统(ji) 竟然不能容易地实现...,于是我看了看,然后想了想,发现是可以通过sql算出这样一个报表(多亏了postgresql的高阶函数

  • postgresql高级应用之合并单元格的思路详解

    1.写在前面✍ 继上一篇postgresql高级应用之行转列&汇总求和之后想更进一步做点儿复杂的(圖表暫且不論哈

  • Python实现二维数组按照某行或列排序的方法【numpy lexsort】

    本文实例讲述了Python实现二维数组按照某行或列排序的方法.分享给大家供大家参考,具体如下: lexsort支持对数组按指定行或列的顺序排序:是间接排序,lexsort不修改原数组,返回索引. (对应lexsort 一维数组的是argsort a.argsort()这么使用就可以:argsort也不修改原数组, 返回索引) 默认按最后一行元素有小到大排序, 返回最后一行元素排序后索引所在位置. 设数组a, 返回的索引ind,ind返回的是一维数组 对于一维数组, a[ind]就是排序后的数组.

  • 在postgresql中通过命令行执行sql文件

    通过命令行执行初始化sql脚本是比较常见的需求,命令行下执行如下操作即可: 若是执行的命名只是创建用户,编辑用户,创建数据库的话可以不指定-d参数. psql -U username -d myDataBase -a -f init.sql 如果是远程数据库加入-h参数指定主机地址即可 psql -h host -U username -d myDataBase -a -f init.sql 补充:PostgreSQL操作-psql基本命令 一.建立数据库连接 接入PostgreSQL数据库:

  • MySQL 行转列详情

    目录 一.行转列SQL写法 二.如果领导@你,让你在结果集中加上总数列呢? 三.领导又双叒叕@你改需求 四.结束语 附录:创建表结构&测试数据SQL   MySQL行转列,对经常处理数据的同学们来说,一定是不陌生的,甚至是印象深刻,因为它大概率困扰过你,让你为之一愣~ 但当你看到本文后,这个问题就不在是问题,及时收藏,以后谁再问你这个问题,直接甩他脸上,粘贴即用. 首先,我们看一下咱们的测试表数据和预期查询的结果: mysql> SELECT * FROM t_gaokao_score; +

  • python按列索引提取文件夹内所有excel指定列汇总(示例代码)

    目录 前言 一.情景描述 二.python汇总 总结 前言 一.情景描述 情景一:文件夹内有很多excel数据,包含的数据格式一样,我们需要提取每个文件中指定的几列数据汇总到一个文件中(因为是按列索引提取,所以列的顺序可以不一样) 汇总后: 二.python汇总 注意事项: 文件所在文件夹内只能有运行文件.py,和需要汇总的文件,不能有其它文件夹,否则会出现运行错误: 运行第二遍时需要将第一遍运行得到的结果文件res.xlsx删除,否则也会出现运行错误: 代码如下(示例): # -*- codi

  • SQL行转列和列转行代码详解

    行列互转,是一个经常遇到的需求.实现的方法,有case when方式和2005之后的内置pivot和unpivot方法来实现. 在读了技术内幕那一节后,虽说这些解决方案早就用过了,却没有系统性的认识和总结过.为了加深认识,再总结一次. 行列互转,可以分为静态互转,即事先就知道要处理多少行(列);动态互转,事先不知道处理多少行(列). --创建测试环境 USE tempdb; GO IF OBJECT_ID('dbo.Orders') IS NOT NULL DROP TABLE dbo.Orde

  • MySQL存储过程中使用动态行转列

    本文介绍的实例成功的实现了动态行转列.下面我以一个简单的数据库为例子,说明一下. 数据表结构 这里我用一个比较简单的例子来说明,也是行转列的经典例子,就是学生的成绩 三张表:学生表.课程表.成绩表 学生表 就简单一点,学生学号.学生姓名两个字段 CREATE TABLE `student` ( `stuid` VARCHAR(16) NOT NULL COMMENT '学号', `stunm` VARCHAR(20) NOT NULL COMMENT '学生姓名', PRIMARY KEY (`

  • datatable行转列示例分享

    复制代码 代码如下: /// <summary>  /// DataTable行转列  /// </summary>  /// <param name="dtable">需要转换的表</param>  /// <param name="head">转换表表头对应旧表字段(小写)</param>  /// <returns></returns>  public static

随机推荐