文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Oracle中如何实现数据透视表

2023-06-14 09:59

关注

这篇文章主要介绍Oracle中如何实现数据透视表,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

使用 CASE 表达式实现数据透视表

数据透视表的本质就是按照行和列的不同组合进行数据分组,然后对结果进行汇总;因此,它和数据库中的分组(GROUP BY)和聚合函数(COUNT、SUM、AVG 等)的功能非常类似。

我们首先使用以下 GROUP BY 子句对销售数据进行分类汇总:

select coalesce(product, '【全部产品】') "产品",    coalesce(channel, '【所有渠道】') "渠道",    coalesce(to_char(saledate, 'YYYYMM'), '【所有月份】') "月份",    sum(amount) "销量"from sales_datagroup by rollup (product,channel,to_char(saledate, 'YYYYMM'));

以上语句按照产品、渠道以及月份进行汇总;rollup 选项用于生成不同层次的小计、合计以及总计;coalesce 函数用于将汇总行中的 NULL 值显示为相应的信息。查询返回的结果如下:

产品      |渠道      |月份       |销量    |
---------|---------|-----------|-------|
桔子      |京东      |201901    |  41289|
桔子      |京东      |201902    |  43913|
桔子      |京东      |201903    |  49803|
桔子      |京东      |201904    |  49256|
桔子      |京东      |201905    |  64889|
桔子      |京东      |201906    |  62649|
桔子      |京东      |【所有月份】| 311799|
桔子      |店面      |201901    |  41306|
桔子      |店面      |201902    |  37906|
桔子      |店面      |201903    |  48866|
桔子      |店面      |201904    |  48673|
桔子      |店面      |201905    |  58998|
桔子      |店面      |201906    |  58931|
桔子      |店面      |【所有月份】| 294680|
桔子      |淘宝      |201901    |  43488|
桔子      |淘宝      |201902    |  37598|
桔子      |淘宝      |201903    |  48621|
桔子      |淘宝      |201904    |  49919|
桔子      |淘宝      |201905    |  58530|
桔子      |淘宝      |201906    |  64626|
桔子      |淘宝      |【所有月份】| 302782|
桔子      |【所有渠道】|【所有月份】| 909261|
...
香蕉      |【所有渠道】|【所有月份】| 925369|
【全部产品】|【所有渠道】|【所有月份】|2771682|

实际上,我们已经得到了数据透视表的汇总结果,只不过需要将数据按照不同月份显示为不同的列;也就是需要将行转换为列,这个功能可以使用 CASE 表达式实现:

select coalesce(product, '【全部产品】') "产品", coalesce(channel, '【所有渠道】') "渠道",     sum(case to_char(saledate, 'YYYYMM') when '201901' then amount else 0 end) "一月",    sum(case to_char(saledate, 'YYYYMM') when '201902' then amount else 0 end) "二月",    sum(case to_char(saledate, 'YYYYMM') when '201903' then amount else 0 end) "三月",    sum(case to_char(saledate, 'YYYYMM') when '201904' then amount else 0 end) "四月",    sum(case to_char(saledate, 'YYYYMM') when '201905' then amount else 0 end) "五月",    sum(case to_char(saledate, 'YYYYMM') when '201906' then amount else 0 end) "六月",    sum(amount) "总计"from sales_datagroup by rollup (product, channel);

第一个 SUM 函数中的 CASE 表达式只汇总 201901 月份的销量,其他月份销量设置为 0;后面的 SUM 函数依次类推,得到了每个月的销量汇总和所有月份的总计。

产品       |渠道       |一月  |二月   |三月   |四月   |五月  |六月   |总计   |
----------|----------|------|------|------|------|------|------|-------|
桔子       |京东      | 41289| 43913| 49803| 49256| 64889| 62649| 311799|
桔子       |店面      | 41306| 37906| 48866| 48673| 58998| 58931| 294680|
桔子       |淘宝      | 43488| 37598| 48621| 49919| 58530| 64626| 302782|
桔子       |【所有渠道】|126083|119417|147290|147848|182417|186206| 909261|
苹果       |京东      | 38269| 40593| 56552| 56662| 64493| 62045| 318614|
苹果       |店面      | 43845| 40539| 44909| 55646| 56771| 64933| 306643|
苹果       |淘宝      | 42969| 43289| 48769| 58052| 58872| 59844| 311795|
苹果       |【所有渠道】|125083|124421|150230|170360|180136|186822| 937052|
香蕉       |京东      | 36879| 36981| 51748| 54801| 64936| 60688| 306033|
香蕉       |店面      | 41210| 39420| 50884| 52085| 60249| 67597| 311445|
香蕉       |淘宝      | 42468| 41955| 52780| 54971| 56504| 59213| 307891|
香蕉       |【所有渠道】|120557|118356|155412|161857|181689|187498| 925369|
【全部产品】|【所有渠道】|371723|362194|452932|480065|544242|560526|2771682|

Oracle 中的 decode 函数也可以实现类似 CASE 表达式的功能。

以上实现数据透视表的方法存在一定的局限性,假如还有 7 月份到 12 月份的销量需要统计,我们就需要修改查询语句增加这部分的处理。因此,Oracle 11g 引入了一个新的子句来实现自动的行转列:PIVOT。

使用 PIVOT 子句实现数据透视表

Oracle 中的 PIVOT 子句用于将行转换为列,基本语法如下:

SELECT col1, col2, ...FROM tblPIVOT ( pivot_clause, pivot_for_clause, pivot_in_clause);

PIVOT 子句包含 3 个部分:

对于上文中的示例,我们可以使用以下 PIVOT 子句:

with d(saledate, product, channel, amount) as ( select to_char(saledate, 'YYYYMM'),     product,     channel,     amount from sales_data)select *from dpivot ( sum(amount) for saledate in ('201901', '201902', '201903', '201904', '201905', '201906'))order by product, channel;

其中,PIVOT 子句按照月份对销量进行汇总并且将月份转换为列显示,返回的结果如下:

PRODUCT  |CHANNEL |'201901'|'201902'|'201903'|'201904'|'201905'|'201906'|
---------|--------|--------|--------|--------|--------|--------|--------|
桔子     |京东     |   41289|   43913|   49803|   49256|   64889|   62649|
桔子     |店面     |   41306|   37906|   48866|   48673|   58998|   58931|
桔子     |淘宝     |   43488|   37598|   48621|   49919|   58530|   64626|
苹果     |京东     |   38269|   40593|   56552|   56662|   64493|   62045|
苹果     |店面     |   43845|   40539|   44909|   55646|   56771|   64933|
苹果     |淘宝     |   42969|   43289|   48769|   58052|   58872|   59844|
香蕉     |京东     |   36879|   36981|   51748|   54801|   64936|   60688|
香蕉     |店面     |   41210|   39420|   50884|   52085|   60249|   67597|
香蕉     |淘宝     |   42468|   41955|   52780|   54971|   56504|   59213|

接下来我们需要增加一个总计行和总计列,为此可以先将 sales_data 数据进行分组统计然后再使用 PIVOT 子句进行转换:

with d(saledate, product, channel, amount) as ( select to_char(saledate, 'YYYYMM'),     product,     channel,     sum(amount) from sales_data group by rollup (to_char(saledate, 'YYYYMM'), product, channel)), pt as ( select * from d pivot (  sum(amount)  for saledate  in ('201901' s01, '201902' s02, '201903' s03, '201904' s04, '201905' s05, '201906' s06) ))select coalesce(product, '【全部产品】') "产品",    coalesce(channel, '【所有渠道】') "渠道",    s01 "一月", s02 "二月", s03 "三月", s04 "四月", s05 "五月", s06 "六月",    s01+s02+s03+s04+s05+s06 "总计"from ptorder by product, channel;

我们在 PIVOT 子句返回的结果之上增加了一个 SELECT 查询,并且修改了返回字段的名称,让结果更加接近 EXCEL 数据透视表:

产品       |渠道       |一月  |二月   |三月   |四月   |五月  |六月   |总计   |
----------|----------|------|------|------|------|------|------|-------|
桔子       |京东      | 41289| 43913| 49803| 49256| 64889| 62649| 311799|
桔子       |店面      | 41306| 37906| 48866| 48673| 58998| 58931| 294680|
桔子       |淘宝      | 43488| 37598| 48621| 49919| 58530| 64626| 302782|
桔子       |【所有渠道】|126083|119417|147290|147848|182417|186206| 909261|
苹果       |京东      | 38269| 40593| 56552| 56662| 64493| 62045| 318614|
苹果       |店面      | 43845| 40539| 44909| 55646| 56771| 64933| 306643|
苹果       |淘宝      | 42969| 43289| 48769| 58052| 58872| 59844| 311795|
苹果       |【所有渠道】|125083|124421|150230|170360|180136|186822| 937052|
香蕉       |京东      | 36879| 36981| 51748| 54801| 64936| 60688| 306033|
香蕉       |店面      | 41210| 39420| 50884| 52085| 60249| 67597| 311445|
香蕉       |淘宝      | 42468| 41955| 52780| 54971| 56504| 59213| 307891|
香蕉       |【所有渠道】|120557|118356|155412|161857|181689|187498| 925369|
【全部产品】|【所有渠道】|371723|362194|452932|480065|544242|560526|2771682|

PIVOT 子句也可以一次执行多个聚合操作,或者按照多个字段进行分组。例如:

with d(saledate, product, channel, amount) as ( select to_char(saledate, 'YYYYMM'), product, channel, amount from sales_data where to_char(saledate, 'YYYYMM') in ('201901', '201902', '201903'))select *from dpivot ( sum(amount) for (channel, saledate) in (('淘宝','201901'), ('店面','201901'), ('京东','201901'),   ('淘宝','201902'), ('店面','201902'), ('京东','201902'),   ('淘宝','201903'), ('店面','201903'), ('京东','201903')));PRODUCT|'淘宝'_'201901'|'店面'_'201901'|'京东'_'201901'|'淘宝'_'201902'|'店面'_'201902'|'京东'_'201902'|'淘宝'_'201903'|'店面'_'201903'|'京东'_'201903'|-------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|香蕉  |     42468|     41210|     36879|     41955|     39420|     36981|     52780|     50884|     51748|桔子  |     43488|     41306|     41289|     37598|     37906|     43913|     48621|     48866|     49803|苹果  |     42969|     43845|     38269|     43289|     40539|     40593|     48769|     44909|     56552|

以上查询返回了按照渠道和月份分组的汇总结果,并且将它们转换为列进行显示。

与 PIVOT 相反的操作是 UNPIVOT,它可以将列转换为行。我们通过以下示例将行专列之后的数据再转换回来:

with d(saledate, product, channel, amount) as ( select to_char(saledate, 'YYYYMM'),     product,     channel,     amount from sales_data),pt as ( select * from d pivot (  sum(amount)  for saledate  in ('201901' "201901", '201902' "201902", '201903' "201903", '201904' "201904", '201905' "201905", '201906' "201906") ))select * from ptunpivot ( amount for saledate IN ("201901", "201902", "201903", "201904", "201905", "201906"));

其中,unpivot 子句也有三个选项,将每个月份代表的列转换为 saledate 字段中的行,并且将对应的数据转换为 amount 字段中的行。以上查询返回的结果如下:

PRODUCT |CHANNEL |SALEDATE|AMOUNT|
--------|--------|--------|------|
桔子     |京东     |201901  | 41289|
桔子     |京东     |201902  | 43913|
桔子     |京东     |201903  | 49803|
桔子     |京东     |201904  | 49256|
桔子     |京东     |201905  | 64889|
桔子     |京东     |201906  | 62649|
香蕉     |店面     |201901  | 41210|
香蕉     |店面     |201902  | 39420|
香蕉     |店面     |201903  | 50884|
香蕉     |店面     |201904  | 52085|
香蕉     |店面     |201905  | 60249|
香蕉     |店面     |201906  | 67597|
...

如果想要解锁更多的 PIVOT 和 UNPIVOT 的使用姿势,可以参考官方文档中的定义和示例。

使用 MODEL 子句实现数据透视表

除了 PIVOT 子句之外,Oracle 还提供一个更加强大的功能:MODEL 子句。简单来说,MODEL 子句可以实现 EXCEL 等电子表格中基于位置和符号的单元格引用以及复杂的公式计算。

完整的 MODEL 子句比较复杂,我们直接看一个示例:

with d(saledate, product, channel, amount) as ( select to_char(saledate, 'YYYYMM'), product, channel, sum(amount) from sales_data group by rollup (to_char(saledate, 'YYYYMM'), product, channel))select coalesce(product, '【全部产品】') "产品",    coalesce(channel, '【所有渠道】') "渠道",    s201901 "一月", s201902 "二月", s201903 "三月", s201904 "四月", s201905 "五月", s201906 "六月",    stotal "总计"from dmodel  return updated rows partition by (product, channel) dimension by (saledate) measures (amount, 0 s201901, 0 s201902, 0 s201903, 0 s201904, 0 s201905, 0 s201906, 0 stotal) unique dimension rules upsert all (s201901[0] = amount['201901'],  s201902[0] = amount['201902'],  s201903[0] = amount['201903'],  s201904[0] = amount['201904'],  s201905[0] = amount['201905'],  s201906[0] = amount['201906'],  stotal[0] = sum(amount)[saledate between '201901' and '201906'])order by product, channel;

首先,通过 with 子句获得基本数据。然后使用 model 子句实现行专列;return updated rows 表示只返回计算模型更新和插入的数据,partition by 用于定义分区(产品和渠道),每个分区独立计算;dimension by 指定度量的维度(月份);measures 定义度量,amount 来自源表,0 s201901 表示创建一个度量 s201901 并初始化为 0;unique dimension 表示 partition by 加 dimension by 字段可以唯一确定模型中的每个单元格;rules 用于定义给每个度量赋值的表达式,upsert all 表示更新已有的单元格,如果不存在则创建单元格;s201901[0] 是通过位置对单元格的引用(维度为 1),amount[‘201901'] 表示月份 201901 对应的 amount 字段值,stotal[0] 是所有月份的总和。

以上语句返回的结果如下:

产品       |渠道       |一月  |二月   |三月   |四月   |五月  |六月   |总计   |
----------|----------|------|------|------|------|------|------|-------|
桔子       |京东      | 41289| 43913| 49803| 49256| 64889| 62649| 311799|
桔子       |店面      | 41306| 37906| 48866| 48673| 58998| 58931| 294680|
桔子       |淘宝      | 43488| 37598| 48621| 49919| 58530| 64626| 302782|
桔子       |【所有渠道】|126083|119417|147290|147848|182417|186206| 909261|
苹果       |京东      | 38269| 40593| 56552| 56662| 64493| 62045| 318614|
苹果       |店面      | 43845| 40539| 44909| 55646| 56771| 64933| 306643|
苹果       |淘宝      | 42969| 43289| 48769| 58052| 58872| 59844| 311795|
苹果       |【所有渠道】|125083|124421|150230|170360|180136|186822| 937052|
香蕉       |京东      | 36879| 36981| 51748| 54801| 64936| 60688| 306033|
香蕉       |店面      | 41210| 39420| 50884| 52085| 60249| 67597| 311445|
香蕉       |淘宝      | 42468| 41955| 52780| 54971| 56504| 59213| 307891|
香蕉       |【所有渠道】|120557|118356|155412|161857|181689|187498| 925369|
【全部产品】|【所有渠道】|371723|362194|452932|480065|544242|560526|2771682|

MODEL 子句允许通过分区(PARTITION BY)和维度(DIMENSION BY)创建一个多维数组,并且通过指定规则(RULES)来操作和更新数组中单元格中的度量值(MEASURES)。其中,规则支持通配符和循环迭代,度量可以使用聚合函数和窗口函数。

MODEL 子句完整的使用姿势请参考官方文档。

以上是“Oracle中如何实现数据透视表”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网行业资讯频道!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯