使用t-sql进行枢轴转换

vha*_*lgi 9 sql t-sql ssis sql-server-2008 business-intelligence

SSIS有一个名为Pivot转换的任务,它将列更改为行,但是如何使用t-sql在sql server中执行相同的任务?

这是我的样本表

location product qty
-----------------------
delhi     PEPSI   100
GURGAON   CAKE    200
NOIDA     APPLE   150
delhi     cake    250
Run Code Online (Sandbox Code Playgroud)

因此,在使用ssis工具将枢轴转换为ON位置作为setkey并将产品作为枢轴键之后,o/p变为

location pepsi cake apple
delhi     100 null null
GURGAON   null 200 null 
NOIDA     null null 150 
delhi     null 250  null
Run Code Online (Sandbox Code Playgroud)

Mah*_*mal 9

PIVOT像这样使用表运算符:

SELECT *
FROM tablename
PIVOT
(
  MAX(qty)
  FOR product IN([pepsi], [cake], [apple])
) as p;
Run Code Online (Sandbox Code Playgroud)

注意:

  • 如果你想获得总和使用或任何其他聚合函数,我使用了MAX聚合函数.qtySUM

  • 您必须手动编写要旋转的列的值,如果要动态执行此操作而不是手动编写,则必须使用动态sql来执行此操作.

像这样:

DECLARE @cols AS NVARCHAR(MAX);
DECLARE @query AS NVARCHAR(MAX);

select @cols = STUFF((SELECT distinct ',' +
                        QUOTENAME(product)
                      FROM tablename
                      FOR XML PATH(''), TYPE
                     ).value('.', 'NVARCHAR(MAX)') 
                        , 1, 1, '');

SELECT @query = 'SELECT *
FROM tablename
PIVOT
(
  MAX(qty)
  FOR product IN(' + @cols + ')) AS p;';

execute(@query);
Run Code Online (Sandbox Code Playgroud)

  • +1为动态sql示例 (2认同)

Dee*_*kha 8

数据透视请求涉及三个逻辑处理阶段,每个阶段都包含相关元素

  1. 分组阶段
  2. 传播阶段
  3. 以及具有关联聚合元素和聚合函数的聚合阶段.

因此,在您的案例中根据需求映射这些阶段:

  1. 分组必须完成 ‘Location’
  2. 传播必须基于‘Product’列值进行,最终列名称为:'Pepsi','Cake','Apple'.
  3. ‘Qty’ 值将被聚合以产生用于分组和扩展元素的交叉值

将这些值放在标准的Pivot语句中:

SELECT ...
FROM <source_table_or_table_expression>
PIVOT(<agg_func>(<aggregation_element>)
FOR <spreading_element>
IN (<list_of_target_columns>)) AS <result_table_alias>
Run Code Online (Sandbox Code Playgroud)

您的查询变为:

select location ,[PEPSI], [CAKE],[APPLE]
from table1
pivot (sum(qty)
       for product
       in ( [PEPSI], [CAKE],[APPLE])) AS T
Run Code Online (Sandbox Code Playgroud)

重要的是要注意,使用PIVOT运算符时,您不会显式指定分组元素,从而无需在查询中使用GROUP BY.PIVOT运算符隐式地将分组元素计算为源表(或表表达式)中未指定为扩展元素或聚合元素的所有属性.因此,您必须确保PIVOT运算符的源表除了分组,传播和聚合元素之外没有任何属性,因此在指定传播和聚合元素之后,剩下的唯一属性是您打算作为分组元素的属性.您可以通过不直接将PIVOT运算符应用于原始表来实现此目的,而是将表单表达式仅包含表示旋转元素的属性而不包含其他元素.

select location ,[PEPSI], [CAKE],[APPLE]
from (select location,product,qty 
      from table1 ) as SourceTable
      pivot (sum(qty)
           for product
           in ( [PEPSI], [CAKE],[APPLE])) AS T
Run Code Online (Sandbox Code Playgroud)

希望这有助于更好地理解Pivot运营商!

编辑:添加了Unpivot运算符概念:

与Pivoting一样,Unpivoting也涉及3个逻辑阶段:

  1. 制作副本
  2. 提取元素
  3. 消除不相关的交叉记录

将这些值放在标准的Unpivot语句中:

SELECT ...
FROM <source_table_or_table_expression>
UNPIVOT(<target_col_to_hold_source_col_values>
FOR <target_col_to_hold_source_col_names> IN(<list_of_source_columns>)) AS
<result_table_alias>;
Run Code Online (Sandbox Code Playgroud)

根据您的案例中的要求映射这些阶段:

  1. <target_col_to_hold_source_col_values>=将保存源列值的列的名称,即:保存列值,[Pepsi], [Cake],[Apple]即100,250 ......您希望将一个列作为:Qty
  2. <target_col_to_hold_source_col_names>=将保存源列名称的列的名称,即:保存[Pepsi], [Cake],[Apple]要使用一列的列名称:product
  3. <list_of_source_columns> =您感兴趣的源表中列的名称,即: [Pepsi], [Cake],[Apple]

您的查询变为:

SELECT location,product,qty
FROM #temp
UNPIVOT(qty
        FOR product  
        IN([Pepsi],[Cake],[Apple])) AS U;
Run Code Online (Sandbox Code Playgroud)

我在临时表中添加了上面的Pivot语句的结果#temp.

这里要注意的重要一点是: 取消透视数据透视表无法恢复原始表,因为透视会导致由于聚合而丢失详细信息.