news 2026/5/1 10:32:59

如何在 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/5/1 6:28:59

Intel平台中eSPI与LPC对比:通俗解释

从LPC到eSPI:一场被低估的“引脚革命”你有没有想过,为什么现在的笔记本越来越薄,主板却能塞进更多功能?为什么BIOS更新失败的概率似乎比十年前低了不少?这些变化背后,有一项默默无闻但至关重要的技术升级—…

作者头像 李华
网站建设 2026/4/30 20:06:51

PaddlePaddle镜像如何部署到华为云昇腾环境?

PaddlePaddle镜像如何部署到华为云昇腾环境? 在国产化替代浪潮席卷各行各业的今天,越来越多企业开始关注“AI全栈自主可控”的落地路径。尤其是在金融、政务、能源等对安全性要求极高的领域,单纯依赖国外深度学习框架与GPU硬件的技术路线已难…

作者头像 李华
网站建设 2026/5/1 5:52:47

Step-GUI 技术报告解读

模型训练、标准化接口、真实场景评估 1、数据生成:如何高效、低成本地获取可靠训练数据 2、部署协议:如何安全、标准地部署成为新问题;敏感数据(如屏幕截图)最好能留在本地设备处理。 3、场景评测:如何科学…

作者头像 李华
网站建设 2026/5/1 8:15:54

多种类型Agent 工具调用机制讲解

概述 工具调用是 Agent 与外部世界交互的核心机制。本教程将详细讲解整个工具调用的完整流程。一、什么是"工具"? 工具就是普通的 Python 函数,预先定义在 tools.py 中。 # tools/tools.pydef web_search(query: str, search_engine: str &qu…

作者头像 李华
网站建设 2026/5/1 5:50:31

3分钟让你的Windows桌面焕然一新:任务栏透明美化终极指南

3分钟让你的Windows桌面焕然一新:任务栏透明美化终极指南 【免费下载链接】TranslucentTB 项目地址: https://gitcode.com/gh_mirrors/tra/TranslucentTB 厌倦了千篇一律的Windows默认界面?想要一个既美观又实用的个性化桌面?今天就来…

作者头像 李华