news 2026/3/27 3:55:06

如何在 SQL 中创建 Pivot 表

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何在 SQL 中创建 Pivot 表

原文:towardsdatascience.com/how-to-pivot-tables-in-sql-88ef2ada5d96?source=collection_archive---------2-----------------------#2024-06-12

数据科学、SQL、ETL

SQL 中创建 Pivot 表的全面指南,以提升数据分析能力

https://medium.com/@yunglinchang?source=post_page---byline--88ef2ada5d96--------------------------------https://towardsdatascience.com/?source=post_page---byline--88ef2ada5d96-------------------------------- Jack Chang

·发布于 Towards Data Science ·阅读时间 11 分钟·2024 年 6 月 12 日

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/3c4d61dc0a7e693c31ccfd1ad8255352.png

图片来源:Mika Baumeister 于 Unsplash

前言

结构化查询语言(SQL)是数据专业人员(如数据科学家和数据分析师)的重要工具,它使他们能够高效、有效地检索、处理和分析大数据集。它是行业中广泛使用的工具,因此是一项重要的技能。在本文中,我将分享如何在 SQL 中创建 Pivot 表。本文是我上一篇文章“Pandas!!!我在第一次现场技术面试后的收获”的延续,文章中我分享了我对 Pandas 的学习心得。

你知道 SQL 可以用于数据分析吗?

在 SQL 中,Pivot 表是一种将数据从行转换为列的技术。

Joan Casteel 的Oracle 12c: SQL书中提到,“Pivot 表是多维数据的呈现。” 使用 Pivot 表,用户可以查看不同数据维度的不同聚合。它是数据分析中的一项强大工具,能够帮助用户以更直观、易于阅读的格式汇总、总结和呈现数据。

例如,一家冰激凌店的老板可能想分析上周哪种口味的冰激凌销量最好。在这种情况下,Pivot 表将非常有用,数据有两个维度——冰激凌口味和星期几。收入可以作为聚合数据进行分析。

冰淇淋店老板可以轻松使用数据透视表比较不同冰淇淋口味和一周中各天的销售情况。数据透视表将转化这些数据,使得发现模式和趋势变得更加容易。有了这些信息,老板可以做出数据驱动的决策,例如增加最受欢迎冰淇淋口味的供应量,或根据需求调整价格。

总体而言,数据透视表是一个出色的数据分析工具,允许用户以更直观和有意义的方式汇总和展示多维数据。它们广泛应用于金融、零售和医疗保健等行业,在这些行业中,通常需要分析大量复杂数据。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/186a5b835a755ae284ea4f11a994e567.png

图片来源:Lama Roscu于Unsplash

概览

本文将基于 Oracle 中的分析函数,通常是“PIVOT”函数。组织的内容旨在全面展示在不同情境下如何使用 SQL 中的数据透视表。我们不仅会介绍创建数据透视表的最简单方法,还会讲解如何利用 PIVOT 函数以最简便和最常见的方式完成任务。最后,我还会讨论 PIVOT 函数的一些局限性。

仅供参考:

**REGION**(RegionID,RDescription)**TERRITORIES**(TerritoryID,TDescription,RegionID@)**CATEGORIES**(CategoryID,CategoryName,Description)**SUPPLIERS**(SupplierID,CompanyName,ContactName,ContactTitle,Address,City,Region,PostalCode,Country,Phone)**CUSTOMERS**(CustomerID,CompanyName,ContactName,ContactTitle,Address,City,Region,PostalCode,Country,Phone)**SHIPPERS**(ShipperID,CompanyName,Phone)**PRODUCTS**(ProductID,ProductName,SupplierID@,CategoryID@,QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder,ReorderLevel,Discontinued)**EMPLOYEES**(EmployeeID,LastName,FirstName,Title,BirthDate,HireDate,Address,City,RegionID@,PostalCode,Country,HomePhone,Extension,ReportsTo@)**EMPLOYEETERRITORIES**(EmployeeID@,TerritoryID@)**ORDERS**(OrderID,CustomerID@,EmployeeID@,TerritoryID@,OrderDate,RequiredDate,ShippedDate,ShipVia@,Freight,ShipName,ShipAddress,ShipCity,ShipRegion,ShipPostalCode,ShipCountry)**ORDERDETAILS**(OrderID@,ProductID@,UnitPrice,Quantity,Discount)

不再赘述,让我们开始吧!

使用“DECODE”的数据透视表

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/74a9451ab9ff3d7249015797d4488746.png

图片来源:Jean-Philippe Delberghe于Unsplash

最原始的数据透视表方法是利用函数:DECODE()。DECODE()函数类似于 if else 语句。它将输入与每个值进行比较,并产生一个输出。

DECODE(input, value1, return1, value2, return2, …, default)

当我们知道 DECODE()如何工作时,就该制作我们的第一个透视表了。

第一版:不带总计列和总计行的透视表

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/01c28e4ecd251f365a719f825518832c.png

不带总计列和总计行的透视表,来源:我

使用 DECODE(),我们可以为冰淇淋店老板绘制一个透视表的伪代码。当“星期几”与每个工作日匹配时,DECODE()返回当天的收入;如果不匹配,则返回 0。

SELECT ice cream flavor,SUM(DECODE(day of the week,'Monday',revenue,0))AS MONDAY,SUM(DECODE(day of the week,'Tuesday',revenue,0))AS TUESDAY,SUM(DECODE(day of the week,'Wednesday',revenue,0))AS WEDNESDAY,SUM(DECODE(day of the week,'Thursday',revenue,0))AS THURSDAY,SUM(DECODE(day of the week,'Friday',revenue,0))AS FRIDAY,SUM(DECODE(day of the week,'Saturday',revenue,0))AS SATURDAY,SUM(DECODE(day of the week,'Sunday',revenue,0))AS SUNDAY FROM ice cream shop dataset WHERE date between last Mondayandlast Sunday;

第二版:带有总计列和总计行的透视表

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/3a58fe26e6b3c13ffbe6a4ba3bddd4a5.png

带有总计列和总计行的透视表,来源:我

干得好!现在冰淇淋店老板想了解更多关于上周销售情况的信息。你可以通过添加总计列和总计行来升级你的透视表。

这可以通过在 GROUP BY 语句中使用GROUPING SETS 表达式来实现。GROUPING SETS 表达式定义了多个 GROUP BY 聚合的标准。

GROUPING SETS (属性 1,…,())

SELECT NVL(ice cream flavor,'TOTAL')"ICE CREAM FLAVOR",SUM(DECODE(day of the week,'Monday',revenue,0))AS MONDAY,SUM(DECODE(day of the week,'Tuesday',revenue,0))AS TUESDAY,SUM(DECODE(day of the week,'Wednesday',revenue,0))AS WEDNESDAY,SUM(DECODE(day of the week,'Thursday',revenue,0))AS THURSDAY,SUM(DECODE(day of the week,'Friday',revenue,0))AS FRIDAY,SUM(DECODE(day of the week,'Saturday',revenue,0))AS SATURDAY,SUM(DECODE(day of the week,'Sunday',revenue,0))AS SUNDAY,SUM(revenue)AS TOTAL FROM ice cream shop dataset WHERE date between last Mondayandlast Sunday GROUP BY GROUPING SETS(ice cream flavor,());

注意:NVL()将由()创建的空值行替换为“TOTAL”。如果你不熟悉NVL(),它只是一个用来替换空值的函数。

计算总计列的另一种方法是将从周一到周日的所有收入加起来:

SUM(DECODE(day of the week,'Monday',revenue,0))+SUM(DECODE(day of the week,'Tuesday',revenue,0))+SUM(DECODE(day of the week,'Wednesday',revenue,0))+SUM(DECODE(day of the week,'Thursday',revenue,0))+SUM(DECODE(day of the week,'Friday',revenue,0))+SUM(DECODE(day of the week,'Saturday',revenue,0))+SUM(DECODE(day of the week,'Sunday',revenue,0))AS TOTAL

第三版:带有总计列和总计行及其他总计的透视表

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/b51145e9666531e26b0b454773076572.png

带有总计列和总计行及其他总计的透视表,来源:我

假设冰淇淋店老板想要在你提供的透视表中再加一列:每种口味冰淇淋的购买总数。没问题!你可以用相同的概念再添加一个“TOTAL”列!

SELECT NVL(ice cream flavor,'TOTAL')"ICE CREAM FLAVOR",SUM(DECODE(day of the week,'Monday',revenue,0))AS MONDAY,SUM(DECODE(day of the week,'Tuesday',revenue,0))AS TUESDAY,SUM(DECODE(day of the week,'Wednesday',revenue,0))AS WEDNESDAY,SUM(DECODE(day of the week,'Thursday',revenue,0))AS THURSDAY,SUM(DECODE(day of the week,'Friday',revenue,0))AS FRIDAY,SUM(DECODE(day of the week,'Saturday',revenue,0))AS SATURDAY,SUM(DECODE(day of the week,'Sunday',revenue,0))AS SUNDAY,SUM(revenue)AS TOTAL,SUM(purchase ID)"OTHER TOTAL"FROM ice cream shop dataset WHERE date between last Mondayandlast Sunday GROUP BY GROUPING SETS(ice cream flavor,());

现在你已经知道如何使用 DECODE()做透视表了,接下来让我们尝试三个关于 Northwind 数据集的练习吧!

Q1. 假设我们想找出每个原籍国的员工在各个区域的服务情况。

为了拆解这个问题,首先,我们可以查询 REGION 表中的所有不同区域,并检查员工来自哪些国家。

SELECT DISTINCT REGIONID||' '||RDescription AS REGION FROM REGION ORDER BY1;

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/3627116e1d54ed0917364c2a13a43fe5.png

SELECT DISTINCT Country FROM EMPLOYEES ORDER BY1;

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/80132a8d40c683c0db3caebce861de5a.png

我们将需要为这个问题制作一个 2 * 4 的透视表。

接下来,我们可以使用 DECODE()来制作透视表。下面概述了一个示例答案和输出:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/2961edeea876bc9ccf18d701f9e086b6.png

SELECT NVL(Country,'TOTAL')AS COUNTRY,SUM(DECODE(LOWER(REGIONID||' '||RDescription),'1 eastern',1,0))"1 EASTERN",SUM(DECODE(LOWER(REGIONID||' '||RDescription),'2 western',1,0))"2 WESTERN",SUM(DECODE(LOWER(REGIONID||' '||RDescription),'3 northern',1,0))"3 NORTHERN",SUM(DECODE(LOWER(REGIONID||' '||RDescription),'4 southern',1,0))"4 SOUTHERN",SUM(EmployeeID)AS TOTAL FROM EMPLOYEES JOIN REGION USING(REGIONID)GROUP BY GROUPING SETS(Country,());

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/1c753723386af8721f3b7d2ea9cb6ec6.png

--Q1 SELECT Country,SUM(DECODE(LOWER(REGIONID||' '||RDescription),'1 eastern',1,0))"1 EASTERN",SUM(DECODE(LOWER(REGIONID||' '||RDescription),'2 western',1,0))"2 WESTERN",SUM(DECODE(LOWER(REGIONID||' '||RDescription),'3 northern',1,0))"3 NORTHERN",SUM(DECODE(LOWER(REGIONID||' '||RDescription),'4 southern',1,0))"4 SOUTHERN",SUM()AS TOTAL FROM EMPLOYEES JOIN REGION USING(REGIONID)GROUP BY Country;

Q2. 对于 2010 年中的每个月,显示每个员工处理的订单收入。此外,四舍五入到最接近的美元,并显示总收入和订单总数。

--Q2 COLUMN EMPLOYEE FORMAT A18 SELECT NVL(EmployeeID||' '||FirstName||' '||LastName,'TOTAL')AS EMPLOYEE,TO_CHAR(SUM(DECODE(EXTRACT(MONTH FROM OrderDate),1,(UnitPrice*Quantity-Discount),0)),'$990')AS JAN,TO_CHAR(SUM(DECODE(EXTRACT(MONTH FROM OrderDate),2,(UnitPrice*Quantity-Discount),0)),'$990')AS FEB,TO_CHAR(SUM(DECODE(EXTRACT(MONTH FROM OrderDate),3,(UnitPrice*Quantity-Discount),0)),'$990')AS MAR,TO_CHAR(SUM(DECODE(EXTRACT(MONTH FROM OrderDate),4,(UnitPrice*Quantity-Discount),0)),'$990')AS APR,TO_CHAR(SUM(DECODE(EXTRACT(MONTH FROM OrderDate),5,(UnitPrice*Quantity-Discount),0)),'$990')AS MAY,TO_CHAR(SUM(DECODE(EXTRACT(MONTH FROM OrderDate),6,(UnitPrice*Quantity-Discount),0)),'$990')AS JUN,TO_CHAR(SUM(DECODE(EXTRACT(MONTH FROM OrderDate),7,(UnitPrice*Quantity-Discount),0)),'$99,990')AS JUL,TO_CHAR(SUM(DECODE(EXTRACT(MONTH FROM OrderDate),8,(UnitPrice*Quantity-Discount),0)),'$99,990')AS AUG,TO_CHAR(SUM(DECODE(EXTRACT(MONTH FROM OrderDate),9,(UnitPrice*Quantity-Discount),0)),'$99,990')AS SEP,TO_CHAR(SUM(DECODE(EXTRACT(MONTH FROM OrderDate),10,(UnitPrice*Quantity-Discount),0)),'$99,990')AS OCT,TO_CHAR(SUM(DECODE(EXTRACT(MONTH FROM OrderDate),11,(UnitPrice*Quantity-Discount),0)),'$99,990')AS NOV,TO_CHAR(SUM(DECODE(EXTRACT(MONTH FROM OrderDate),12,(UnitPrice*Quantity-Discount),0)),'$99,990')AS DEC,TO_CHAR(SUM((UnitPrice*Quantity-Discount)),'$999,990')AS TOTAL FROM ORDERS JOIN ORDERDETAILS USING(OrderID)JOIN EMPLOYEES USING(EmployeeID)WHERE EXTRACT(YEAR FROM OrderDate)=2010GROUP BY GROUPING SETS(EmployeeID||' '||FirstName||' '||LastName,())ORDER BY1;

注意:请注意,FORMAT 命令和 TO_CHAR()函数是用于格式化目的。如果你想了解更多信息,请查看 Oracle 网站上的格式模型和格式化 SQL*Plus 报告部分。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/20c3ea352b3155d73bf77da29769b3dc.png

使用“PIVOT”的透视表

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/93e298803a661c1d579b990d24846251.png

图片由Noah Windler拍摄,来源于Unsplash

现在你已经知道如何使用 DECODE()创建透视表,我们可以继续介绍 Oracle 在 11g 版本中引入的 PIVOT()子句。

SELECT *

FROM (查询)

PIVOT (aggr FOR 列 IN (value1, value2, …)

);

让我们回到冰淇淋店的例子。以下是如何使用 PIVOT()子句来实现:

第一版:没有总计列和行的透视表

SELECT*FROM(SELECT day of the week,ice cream flavor,revenue FROM ice cream shop dataset WHERE date between last Mondayandlast Sunday)PIVOT(SUM(revenue)FOR day of the week IN('Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'));

第二版:带有总计列和行的透视表

如果你想在透视表中添加一个总计列,使用 NVL()函数是一个很好的方法。

SELECT*FROM(SELECT NVL(ice cream flavor,'TOTAL')AS ice cream flavor,NVL(day of the week,-1)AS DOW,SUM(revenue)AS REV FROM ice cream shop dataset WHERE date between last Mondayandlast Sunday GROUP BY CUBE(ice cream flavor,day of the week))PIVOT(SUM(REV)FOR DOW IN('Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday',-1AS TOTAL));

第三版:带有总计列和行以及其他总计的透视表

当其他总计出现时,只有一种方法可以解决问题,那就是使用 JOIN()子句。

SELECT ice cream flavor,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday,TOTAL,OTHER TOTAL FROM(SELECT NVL(ice cream flavor,'TOTAL')AS ice cream flavor,NVL(day of the week,-1)AS DOW,SUM(revenue)AS REV FROM ice cream shop dataset WHERE date between last Mondayandlast Sunday GROUP BY CUBE(ice cream flavor,day of the week))PIVOT(SUM(REV)FOR DOW IN('Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday',-1AS TOTAL))JOIN(SELECT NVL(ice cream flavor,'TOTAL')AS ice cream flavor,SUM(purchase ID)"OTHER TOTAL"FROM ice cream shop dataset WHERE date between last Mondayandlast Sunday GROUP BY ROLLUP(ice cream flavor))USING(ice cream flavor);

注意:在上面的伪代码中,我们使用了 GROUP BY 中的 CUBE 和 ROLLUP 扩展。简短的解释就可以说明问题。

一旦我们了解了 PIVOT()子句的工作原理,你能否用我们在第一部分中提供的 Northwind 数据集进行练习?

Q1. 假设我们想找出每个员工在各自的原籍国中,在哪些区域服务。

--Q1--Try it out!

Q2. 对于 2010 年每个月,显示每个员工处理的订单收入。同时,四舍五入到最接近的美元,并显示总收入和总订单数。

--Q2--Try it out!

结语

在本指南中,我们探讨了 SQL 中透视表的强大功能,重点介绍了**DECODE()PIVOT()**函数。我们首先介绍了透视表及其在将行转换为列以进行更深入的数据分析中的重要性。接着,我们演示了如何使用 DECODE()创建透视表,并详细讨论了 Oracle 11g 中引入的更简化的 PIVOT()函数,该函数简化了透视表的创建过程。通过应用这些技术,我们展示了如何通过实际示例(如冰淇淋店数据集)高效地分析多维数据。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/99f5eaa3aca6a02bd505db3ffccfd7dd.png

图片由karl muscat提供,来源于Unsplash

回顾与收获

  1. 使用 DECODE()的透视表:一种使用 DECODE()函数手动进行数据透视的基本方法。

  2. 使用 PIVOT()的透视表:利用 PIVOT()函数创建更加高效且易于阅读的透视表。

随时在评论区分享你的答案。我喜欢学习数据,并反思(写下)我在实际应用中学到的东西。如果你喜欢这篇文章,请为它点赞,表示支持。如果你有更多话题想要讨论,可以通过LinkedIn和Twitter联系我。也欢迎在 Medium 上关注我,未来会有更多数据科学相关文章发布!

来数据科学乐园一起玩吧!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/22 10:04:53

PaddlePaddle镜像支持稀疏训练吗?减少90%参数的方法

PaddlePaddle镜像支持稀疏训练吗?减少90%参数的方法 在当前大模型席卷AI产业的背景下,一个现实问题愈发突出:我们真的需要千亿参数来完成每一个任务吗?当训练一次GPT级别模型的成本足以买下一台特斯拉时,越来越多的企业…

作者头像 李华
网站建设 2026/3/27 10:22:01

PaddlePaddle镜像中的动量(Momentum)优化器调参建议

PaddlePaddle镜像中的动量(Momentum)优化器调参建议 在深度学习项目中,模型训练的稳定性与收敛速度往往直接决定了研发周期和上线效率。尤其是在工业级场景下,一个看似微小的优化器参数设置不当,可能让原本几天就能完成…

作者头像 李华
网站建设 2026/3/24 11:37:35

新手教程:用Arduino读懂SSD1306中文手册并点亮屏幕

从零读懂SSD1306手册:用Arduino点亮OLED的完整实战指南你有没有试过照着网上的教程接好线、烧录代码,结果屏幕就是不亮?或者显示的内容上下颠倒、模糊不清,却不知道问题出在哪?如果你正在用Arduino驱动一块小小的OLED屏…

作者头像 李华
网站建设 2026/3/24 0:48:01

提高效率:Arduino IDE为ESP32定制编译选项的完整示例

如何用platform.local.txt深度定制 ESP32 编译流程?实战指南你有没有遇到过这样的情况:写完一个功能丰富的 Arduino 项目,点击“上传”,结果 IDE 弹出错误:“固件太大,无法烧录!”或者你想用std…

作者头像 李华
网站建设 2026/3/13 8:04:31

PaddlePaddle镜像中的标签平滑(Label Smoothing)作用解析

PaddlePaddle中的标签平滑:从原理到工业实践 在现代深度学习训练中,一个看似微小的技巧——将真实类别标签从“1.0”轻轻往下调一点,竟然能显著提升模型在线上环境的真实表现。这听起来有些反直觉:我们教模型识别猫的时候&#xf…

作者头像 李华