【问题标题】:Pivot transformation using t-sql [closed]使用 t-sql 进行枢轴转换 [关闭]
【发布时间】:2013-10-15 03:31:35
【问题描述】:

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

这是我的示例表

location product qty
-----------------------
delhi     PEPSI   100
GURGAON   CAKE    200
NOIDA     APPLE   150
delhi     cake    250

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

location pepsi cake apple
delhi     100 null null
GURGAON   null 200 null 
NOIDA     null null 150 
delhi     null 250  null

【问题讨论】:

    标签: sql sql-server-2008 tsql ssis business-intelligence


    【解决方案1】:

    像这样使用PIVOT 表运算符:

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

    请注意:

    • 我使用MAX 聚合函数和qty,如果您想获得总和,请改用SUM 或任何其他聚合函数。

    • 您必须手动将列的值写入透视,如果您想动态执行此操作而不是手动写入,则必须使用动态 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);
    

    【讨论】:

    • +1 用于动态 sql 示例
    【解决方案2】:

    一个数据透视请求涉及三个逻辑处理阶段,每个阶段都有关联的元素:

    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>
    

    您的查询变为:

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

    请务必注意,使用 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
    

    希望这有助于更好地理解 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>;
    

    根据您的情况将这些阶段映射到需求:

    1. &lt;target_col_to_hold_source_col_values&gt; = 将保存源列值的列的名称 即:保存列值[Pepsi], [Cake],[Apple] 即 100,250 ...您希望有一个单列:Qty
    2. &lt;target_col_to_hold_source_col_names&gt; = 将保存源列名的列名 即:要保存列名[Pepsi], [Cake],[Apple],您希望有一列:product
    3. &lt;list_of_source_columns&gt; = 您感兴趣的源表中的列名 即:[Pepsi], [Cake],[Apple]

    您的查询变为:

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

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

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

    【讨论】:

    • 一篇关于旋转的非常好的帖子,我希望我有更多的 +1 给你!
    猜你喜欢
    • 1970-01-01
    • 2011-04-26
    • 1970-01-01
    • 2012-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-08
    相关资源
    最近更新 更多