pivot unpivot_静态和动态SQL Pivot和Unpivot关系运算符概述

本文介绍了SQL Pivot和Unpivot运算符,用于转置SQL Server数据。详细讲解了静态和动态使用Pivot和Unpivot的方法,包括如何进行SQL Pivot操作以获取月度和季度销售数据。
摘要由CSDN通过智能技术生成

pivot unpivot

In this article, we’ll walk-through the SQL Pivot and SQL Unpivot operators and how they can be useful to transpose SQL Server data. Also, we’ll discuss both static and dynamic ways to use PIVOT and UNPIVOT relational operators that can be used to transform aggregated distinct values as column(s) in the result-set by specifying all the column values in the PIVOT IN clause.

在本文中,我们将逐步介绍SQL Pivot和SQL Unpivot运算符,以及它们如何对转置SQL Server数据有用。 此外,我们还将讨论使用PIVOT和UNPIVOT关系运算符的静态和动态方式,这些运算符可通过在PIVOT IN子句中指定所有列值来将聚合的不同值转换为结果集中的列。

SQL Server枢轴介绍 (SQL Server pivot Introduction)

There are several ways to transpose a dataset from rows to columns and columns to rows. SQL Pivot is one of the techniques that allows transposing of rows to columns and performs possible aggregations along the way. SQL PIVOT and SQL UNPIVOT relational operators transpose a table-valued two-dimensional data into another form of data. SQL PIVOT transposes a table-valued expression from a unique set of values from one column into multiple columns in the output and performs aggregations. SQL UNPIVOT performs the opposite operation of SQL PIVOT by transforming the columns of a table-valued expression into column values.

有几种方法可以将数据集从行到列以及从列到行进行转置。 SQL Pivot是一种允许将行转置为列并在此过程中执行可能的聚合的技术之一。 SQL PIVOT和SQL UNPIVOT关系运算符将表值的二维数据转换为另一种数据形式。 SQL PIVOT将来自一组唯一值的表值表达式转置为输出中的多个列,并执行聚合。 SQL UNPIVOT通过将表值表达式的列转换为列值来执行SQL PIVOT的相反操作。

In most cases, the static pivoting technique suffices the business requirement. For example, the monthly sales forecast, yearly sales split, quarterly sales aggregation, etc, where the IN clause columns remain static. In some other instances, we need granular details and the table-value expression is more dynamic in nature and all the time new set of the expression are included in the table then dynamic PIVOT would be the best choice.

在大多数情况下,静态旋转技术足以满足业务需求。 例如,月度销售预测,年度销售拆分,季度销售汇总等,其中IN子句列保持不变。 在其他一些情况下,我们需要细粒度的细节,并且表值表达式本质上是更动态的,并且表中始终包含新的表达式集,那么动态PIVOT将是最佳选择。

Note: In the above depiction, we can see that in the process of PIVOT, the column values are rotated from vertical to horizontal and UNPIVOTING is like rotating it from horizontal to vertical.

注意:在以上描述中,我们可以看到在PIVOT的过程中,列值从垂直旋转到水平,而UNPIVOTING就像从水平旋转到垂直。

Syntax

句法

SELECT <non-pivoted column>,

SELECT <非枢轴列>,

[pivot_column_1] AS <column alias>,

[pivot_column_1] AS <列别名>,

[pivot_column_2] AS <column alias>,

[pivot_column_2] AS <列别名>,

[pivot_column_n] AS <column alias>

[pivot_column_n] AS <列别名>

FROM

(

<SELECT QUERY>)

<选择查询>)

AS <Alias for temporary data set>

AS <临时数据集别名>

PIVOT

(

<Aggregate function>( Aggregate column)

<汇总功能>(“汇总”列)

FOR

对于

[<Pivot column will become column headers>]

[<枢轴列将成为列标题>]

IN ( [pivot_column_1], [pivot_column_2],

IN([pivot_column_1],[pivot_column_2],

… [pivot_column_n] )

…[pivot_column_n])

) AS <Pivot table alias>

)AS <数据透视表别名>

< ORDER BY clause>;

<ORDER BY子句>;

SQL Pivot入门 (Getting started with SQL Pivot)

We’re going to start with pivoting and un-pivoting the data. By now you understand what PIVOT and UNPIVOT operators are in SQL Server. In simple terms, it is just another way to describe the process of turning distinct row values into their own columns is known as Pivoting. And the process of turning columns into rows is known as an un-pivoting. 

我们将从数据透视图和数据透视图开始。 到目前为止,您已经了解了SQL Server中的PIVOT和UNPIVOT运算符。 简单来说,这是描述将不同的行值转换为自己的列的过程的另一种方式,称为“透视”。 将列变成行的过程称为固定。

示例1 :如何执行SQL Pivot操作 (Example 1: How to perform a SQL Pivot operation)

Let’s picture the sample dataset derived from the AdventureWorks2014 database. In this case, you just got a simple dataset with SalesYear column along the one quantitative value TotalSales.

让我们对从AdventureWorks2014数据库派生的样本数据集进行图示。 在这种情况下,您只获得了一个带有SalesYear列的简单数据集以及一个定量值TotalSales。

Now, the dataset is ready for pivoting. You’ve got SalesYear in the first column, TotalSales in the second column. If you asked to transpose the data, you have to take every distinct year in the column and these columns become the header of the pivot columns. So, 2011 becomes the first column, 2012 becomes its own column and so on. The actual values from the next column Totalsales, they stick with the pivot column headers. Now, the pivoting table would look like below.

现在,数据集已准备好进行透视。 您在第一列中有SalesYear,在第二列中有TotalSales。 如果要求转置数据,则必须在该列中使用每个不同的年份,这些列将成为数据透视表列的标题。 因此,2011年成为第一列,2012年成为其自己的列,依此类推。 来自下一列Totalsales的实际值将保留在数据透视表列标题中。 现在,数据透视表如下所示。

SELECT * FROM 
(
SELECT YEAR(SOH.OrderDate) as SalesYear,
        SOH.SubTotal as TotalSales
 FROM sales.SalesOrderHeader SOH
     JOIN sales.SalesOrderDetail SOD ON SOH.SalesOrderId = SOD.SalesOrderId
) AS Sales
PIVOT (SUM(TotalSales)
FOR SalesYear IN ([2011],[2012],[2013],[2014]))
as PVT

The following image depicts the input data, Pivot syntax, SQL Pivot, and output results.

下图描述了输入数据,Pivot语法,SQL Pivot和输出结果。

示例2 :如何执行SQL Unpivot操作 (Example 2: How to perform a SQL Unpivot operation)

Let’s now look in the other direction, un-pivoting, which is as simple as going from horizontal to vertical. In this case, you’d take all of those distinct columns that are selected, and it would turn those column headers into their own rows. Pivoting is like rotating from vertical to horizontal. And un-pivoting is like rotating from horizontal to vertical.

现在,让我们从另一个方向来看,即不旋转,就像从水平到垂直一样简单。 在这种情况下,您将选择所有这些不同的列,并将这些列标题转换为自己的行。 旋转就像从垂直旋转到水平一样。 无枢轴旋转就像从水平旋转到垂直一样。

SELECT SalesYear, 
       TotalSales
FROM
(
    SELECT *
    FROM
    (
        SELECT YEAR(SOH.OrderDate) AS SalesYear, 
               SOH.SubTotal AS TotalSales
        FROM sales.SalesOrderHeader SOH
             JOIN sales.SalesOrderDetail SOD ON SOH.SalesOrderId = SOD.SalesOrderId
    ) AS Sales PIVOT(SUM(TotalSales) FOR SalesYear IN([2011], 
                                                      [2012], 
                                                      [2013], 
                                                      [2014])) AS PVT
) T UNPIVOT(TotalSales FOR SalesYear IN([2011], 
                                        [2012], 
                                        [2013], 
                                        [2014])) AS upvt;

In the following example, the pivoted dataset is used to un-pivot the values. The key piece here is this was easy to do in getting transformed because we were able to create a pivot table as an intermediate step and then do the transformation using the unpivot operation.

在以下示例中,使用透视数据集取消透视值。 这里的关键是,转换很容易做到,因为我们能够创建一个数据透视表作为中间步骤,然后使用unpivot操作进行转换。

Note: SQL pivot operation results in transposing the aggregated result into column but whereas SQL unpivot is not an exact reversal of transposing columns into the segregated values of rows. The unpivot operator will not split the aggregated results.

注意:SQL透视操作会导致将聚合结果转置为列,但是SQL unpivot并不是将列转置为行的隔离值的确切逆转。 unpivot运算符不会拆分汇总结果。

示例3 :如何使用SQL Pivot操作获取季度销售额 (Example 3: How to get quarterly sales using SQL pivot operation)

Let’s see a few more examples to understand the pivoting concepts better. In this case, we’ll see how to get quarterly sales data aggregated based on the quarterly sales.

让我们再看一些示例,以更好地理解关键概念。 在这种情况下,我们将了解如何获取基于季度销售额的季度销售额数据。

Before we jump into the solution, it is always recommended to work on creating a dataset for the PIVOT operation.

在我们进入解决方案之前,始终建议为PIVOT操作创建数据集。

The following example gives the aggregated monthly sales spread over the sales year.

以下示例给出了跨销售年度的汇总每月销售。

SELECT YEAR(SOH.OrderDate) AS SalesYear, 
       MONTH(SOH.OrderDate) AS SalesMonth, 
       SUM(SOH.SubTotal) AS TotalSales
FROM sales.SalesOrderHeader SOH
     JOIN sales.SalesOrderDetail SOD ON SOH.SalesOrderId = SOD.SalesOrderId
GROUP BY YEAR(SOH.OrderDate), 
         MONTH(SOH.OrderDate)
ORDER BY YEAR(SOH.OrderDate), 
         MONTH(SOH.OrderDate);

The following output shows the base data

以下输出显示了基本数据

Once you’re ready with the base data, you can apply the PIVOT operator. In the following example, the IN clause accepts a non-numerical character that got generated based on the DATEPART value. The DATEPART value is concatenated with ‘Q’ and then the values are fed to IN clause of PIVOT operator.

一旦准备好基本数据,就可以应用PIVOT运算符。 在下面的示例中,IN子句接受基于DATEPART值生成的非数字字符。 DATEPART值与'Q'串联,然后将值馈送到PIVOT运算符的IN子句。

SELECT SalesYear, 
       ISNULL([Q1], 0) AS Q1, 
       ISNULL([Q2], 0) AS Q2, 
       ISNULL([Q3], 0) AS Q3, 
       ISNULL([Q4], 0) AS Q4, 
       (ISNULL([Q1], 0) + ISNULL([Q2], 0) + ISNULL([Q3], 0) + ISNULL([Q4], 0)) SalesYTD
FROM
(
    SELECT YEAR(SOH.OrderDate) AS SalesYear, 
           CAST('Q'+CAST(DATEPART(QUARTER, SOH.OrderDate) AS VARCHAR(1)) AS VARCHAR(2)) Quarters, 
           SOH.SubTotal AS TotalSales
    FROM sales.SalesOrderHeader SOH
         JOIN sales.SalesOrderDetail SOD ON SOH.SalesOrderId = SOD.SalesOrderId
 ) AS Data PIVOT(SUM(TotalSales) FOR Quarters IN([Q1], 
                                                [Q2], 
                                                [Q3], 
                                                [Q4])) AS pvt
ORDER BY SalesYear;

The following output is a quarterly split of the sales data

以下输出是销售数据的季度划分

示例4 :如何使用SQL透视操作获得月度销售额 (Example 4: How to get monthly sales using a SQL pivot operation)

Let us take a look into another example to see sales split data based on every month. In the following example, the IN clause values are generated as part of the DATEPART function. The DATEPART values are fed to IN clause of PIVOT operator.

让我们看看另一个示例,以查看每个月的销售拆分数据。 在下面的示例中,IN子句值作为DATEPART函数的一部分生成。 DATEPART值被馈送到PIVOT运算符的IN子句。

SELECT SalesYear, 
       ISNULL([1], 0) AS Jan, 
       ISNULL([2], 0) AS Feb, 
       ISNULL([3], 0) AS Mar, 
       ISNULL([4], 0) AS Apr, 
       ISNULL([5], 0) AS May, 
       ISNULL([6], 0) AS Jun, 
       ISNULL([7], 0) AS Jul, 
       ISNULL([8], 0) AS Aug, 
       ISNULL([9], 0) AS Sep, 
       ISNULL([10], 0) AS Oct, 
       ISNULL([11], 0) AS Nov, 
       ISNULL([12], 0) AS Dec, 
       (ISNULL([1], 0) + ISNULL([2], 0) + ISNULL([3], 0) + ISNULL([4], 0) + ISNULL([4], 0) + ISNULL([5], 0) + ISNULL([6], 0) + ISNULL([7], 0) + ISNULL([8], 0) + ISNULL([9], 0) + ISNULL([10], 0) + ISNULL([11], 0) + ISNULL([12], 0)) SalesYTD
FROM
(
    SELECT YEAR(SOH.OrderDate) AS SalesYear, 
           DATEPART(MONTH, SOH.OrderDate) Months,
          SOH.SubTotal AS TotalSales
    FROM sales.SalesOrderHeader SOH
         JOIN sales.SalesOrderDetail SOD ON SOH.SalesOrderId = SOD.SalesOrderId
 ) AS Data PIVOT(SUM(TotalSales) FOR Months IN([1], 
                                                  [2], 
                                                  [3], 
                                                  [4], 
                                                  [5], 
                                                  [6], 
                                                  [7], 
                                                  [8], 
                                                  [9], 
                                                  [10], 
                                                  [11], 
                                                  [12])) AS pvt;

The following output is a monthly split of the sales data

以下输出是销售数据的每月拆分

示例5 :如何使用动态SQL枢轴操作获取每月销售额 (Example 5: How to get monthly sales using dynamic SQL pivot operation)

Let us address the monthly split of sales data using dynamic pivoting. So far, we discussed static pivot operations. In order to convert a static pivot operation to dynamic, we’ve to remove the hardcoded values from the IN clause. First, get the distinct expression from the dataset and then prepare a string by concatenating all the expressions. In the following example, the @columnname is used to concatenate all the expression. The concatenated expression is fed to pivot IN clause. The rest is a simple conversion of static SQL into a dynamic SQL and call @DML using sp_executesql stored procedure.

让我们使用动态数据透视来解决销售数据的每月拆分。 到目前为止,我们讨论了静态枢轴操作。 为了将静态枢轴操作转换为动态操作,我们必须从IN子句中删除硬编码值。 首先,从数据集中获取不同的表达式,然后通过连接所有表达式来准备一个字符串。 在下面的示例中,@ columnname用于连接所有表达式。 串联的表达式被馈送到数据透视IN子句。 剩下的就是将静态SQL轻松转换为动态SQL,并使用sp_executesql存储过程调用@DML。

DECLARE @dml AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX)
 
SELECT @ColumnName= ISNULL(@ColumnName + ',','') 
       + QUOTENAME(Months)
FROM (SELECT DISTINCT  DATEPART(MONTH, SOH.OrderDate) Months
         FROM sales.SalesOrderHeader SOH
         JOIN sales.SalesOrderDetail SOD ON SOH.SalesOrderId = SOD.SalesOrderId
    GROUP BY YEAR(SOH.OrderDate),
DATEPART(MONTH, SOH.OrderDate)) AS Months
 
 --Prepare the PIVOT query using the dynamic 
SET @dml = 
  N'SELECT SalesYear, ' +@ColumnName + ' FROM
  (
  SELECT YEAR(SOH.OrderDate) AS SalesYear, 
           DATEPART(MONTH, SOH.OrderDate) Months,
           SUM(SOH.SubTotal) AS TotalSales
   FROM sales.SalesOrderHeader SOH
         JOIN sales.SalesOrderDetail SOD ON SOH.SalesOrderId = SOD.SalesOrderId
    GROUP BY YEAR(SOH.OrderDate),
    DATEPART(MONTH, SOH.OrderDate)) AS T
    PIVOT(SUM(TotalSales) 
           FOR Months IN (' + @ColumnName + ')) AS PVTTable'
--Print @DynamicPivotQuery
--Execute the Dynamic Pivot Query
EXEC sp_executesql @dml

That’s all for now…

目前为止就这样了…

结语 (Wrapping Up)

Thus far, we’ve demonstrated the basic concepts and several examples of SQL PIVOT and SQL UNPIVOT.

到目前为止,我们已经演示了SQL PIVOT和SQL UNPIVOT的基本概念和几个示例。

The sample is based on the SQL Server adventureworks2014 database. You can give a try and test all the samples yourself. If you’ve any question, please feel free to comment below…

该示例基于SQL Server Adventureworks2014数据库。 您可以尝试自己测试所有样本。 如有任何疑问,请随时在下方评论...

翻译自: https://www.sqlshack.com/static-and-dynamic-sql-pivot-and-unpivot-relational-operator-overview/

pivot unpivot

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值