【问题标题】:Unpivot multiple columns and group into new columns取消透视多个列并分组为新列
【发布时间】:2016-02-21 05:36:55
【问题描述】:

我正在处理具有多个参数的客户数据,例如列中的每个月的预计单位、预计值、数量单位、数量值、Parm 单位、Parm 值。

每个参数都以月份名称为前缀,例如 JAN_Projected units、JAN_ Projected value、JAN_Quantity units、JAN_ Quantity value、JAN_ Parm Units、JAN_ Parm Value。

这是我的表的架构:

CREATE TABLE [dbo].[tbl_forum_data](
    [Sno] [float] NULL,
    [JAN_Projected units] [float] NULL,
    [JAN_Projected value] [float] NULL,
    [JAN_Quantity units] [float] NULL,
    [JAN_Quantity value] [float] NULL,
    [JAN_Parm Units  ] [float] NULL,
    [JAN_Parm Value  ] [float] NULL,
    [FEB_Projected units] [float] NULL,
    [FEB_Projected value] [float] NULL,
    [FEB_Quantity units] [float] NULL,
    [FEB_Quantity value] [float] NULL,
    [FEB_Parm Units  ] [float] NULL,
    [FEB_Parm Value  ] [float] NULL,
    [MAR_Projected units] [float] NULL,
    [MAR_Projected value] [float] NULL,
    [MAR_Quantity units] [float] NULL,
    [MAR_Quantity value] [float] NULL,
    [MAR_Parm Units  ] [float] NULL,
    [MAR_Parm Value  ] [float] NULL
) ON [PRIMARY]

我想根据每个月对每个预计单位、预计值、数量单位、数量值、参数单位和参数值进行分组,如下图所示

如果这不可能,至少我想将列更改为行并将单位分组为单独的列,并将值分组为单独的列,如下所示。

我尝试进行交叉连接,但是我能够将值放入行中。下面是我使用的代码:

select Sno
       ,G.EventName
       ,G.EventDate
from [db_Temp].[dbo].[tbl_forum_data] as T
  cross apply (values ([JAN_Projected units], 'JAN_Projected units'),
([JAN_ Projected value], 'JAN_ Projected value'),
([JAN_Quantity units], 'JAN_Quantity units'),
([JAN_ Quantity value], 'JAN_ Quantity value'),
([JAN_ Parm Units  ], 'JAN_ Parm Units'),
([JAN_ Parm Value  ], 'JAN_ Parm Value'),
([FEB_ Projected units], 'FEB_ Projected units'),
([FEB_ Projected value], 'FEB_ Projected value'),
([FEB_Quantity units], 'FEB_Quantity units'),
([FEB_ Quantity value], 'FEB_ Quantity value'),
([FEB_ Parm Units  ], 'FEB_ Parm Units'),
([FEB_ Parm Value  ], 'FEB_ Parm Value'),
([MAR_ Projected units], 'MAR_ Projected units'),
([MAR_ Projected value], 'MAR_ Projected value'),
([MAR_ Quantity units], 'MAR_ Quantity units'),
([MAR_ Quantity value], 'MAR_ Quantity value'),
([MAR_ Parm Units  ], 'MAR_ Parm Units'),
([MAR_ Parm Value  ], 'MAR_ Parm Value')) as G(EventDate, EventName);

非常感谢任何帮助。提琴手SQL Schema的链接。

【问题讨论】:

    标签: sql-server tsql sql-server-2012 unpivot


    【解决方案1】:

    此脚本显示了两种方法来执行此操作。

    1. 使用CROSS APPLY 生成具有所需列的行
    2. 使用UNPIVOT + 使用MAX(CASE ...) 旋转
    CREATE TABLE #tbl_forum_data(
        [Sno] [float] NULL,
        [JAN_Projected units] [float] NULL, [JAN_Projected value] [float] NULL,[JAN_Quantity units] [float] NULL,
        [JAN_Quantity value] [float] NULL, [JAN_Parm Units  ] [float] NULL,[JAN_Parm Value  ] [float] NULL,
        [FEB_Projected units] [float] NULL, [FEB_Projected value] [float] NULL, [FEB_Quantity units] [float] NULL,
        [FEB_Quantity value] [float] NULL, [FEB_Parm Units  ] [float] NULL, [FEB_Parm Value  ] [float] NULL,
        [MAR_Projected units] [float] NULL, [MAR_Projected value] [float] NULL, [MAR_Quantity units] [float] NULL,
        [MAR_Quantity value] [float] NULL, [MAR_Parm Units  ] [float] NULL, [MAR_Parm Value  ] [float] NULL
    );
    INSERT INTO #tbl_forum_data([Sno],
        [JAN_Projected units],[JAN_Projected value],[JAN_Quantity units],[JAN_Quantity value],[JAN_Parm Units  ],[JAN_Parm Value  ],
        [FEB_Projected units],[FEB_Projected value],[FEB_Quantity units],[FEB_Quantity value],[FEB_Parm Units  ],[FEB_Parm Value  ],
        [MAR_Projected units],[MAR_Projected value],[MAR_Quantity units],[MAR_Quantity value],[MAR_Parm Units  ],[MAR_Parm Value  ]
    )
    VALUES(1,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18);
    
    -- using cross apply/union all
    SELECT
        Sno,[Month],[Projected units],[Projected value],[Quantity units],[Quantity value],[Parm Units],[Parm Value]
    FROM
        #tbl_forum_data
        CROSS APPLY (
            SELECT 'JAN' AS [Month], 0 AS [MonthSort],
                   [JAN_Projected units] AS [Projected units], [JAN_Projected value] AS [Projected value],
                   [JAN_Quantity units]  AS [Quantity units] , [JAN_Quantity value]  AS [Quantity value] ,
                   [JAN_Parm Units  ]    AS [Parm Units]     , [JAN_Parm Value  ]    AS [Parm Value]
            UNION ALL
            SELECT 'FEB' AS [Month], 1 AS [MonthSort],
                   [FEB_Projected units] AS [Projected units], [FEB_Projected value] AS [Projected value],
                   [FEB_Quantity units]  AS [Quantity units] , [FEB_Quantity value]  AS [Quantity value] ,
                   [FEB_Parm Units  ]    AS [Parm Units]     , [FEB_Parm Value  ]    AS [Parm Value]
            UNION ALL
            SELECT 'MAR' AS [Month], 2 AS [MonthSort],
                   [MAR_Projected units] AS [Projected units], [MAR_Projected value] AS [Projected value],
                   [MAR_Quantity units]  AS [Quantity units] , [MAR_Quantity value]  AS [Quantity value] ,
                   [MAR_Parm Units  ]    AS [Parm Units]     , [MAR_Parm Value  ]    AS [Parm Value]
        ) AS up
    ORDER BY
        Sno,[MonthSort];
    
    -- using unpivot / pivot (using MAX(CASE ...) for multi column pivot)
    SELECT
        Sno,[Month],
        [Projected units]=MAX(CASE WHEN category='Projected units' THEN value END),
        [Projected value]=MAX(CASE WHEN category='Projected value' THEN value END),
        [Quantity units]=MAX(CASE WHEN category='Quantity units' THEN value END),
        [Quantity value]=MAX(CASE WHEN category='Quantity value' THEN value END),
        [Parm Units]=MAX(CASE WHEN category='Parm Units  ' THEN value END),
        [Parm Value]=MAX(CASE WHEN category='Parm Value  ' THEN value END)
    FROM
        (
            SELECT
                Sno,[Month]=LEFT(DataPoint,3),category=SUBSTRING(DataPoint,5,LEN(DataPoint)),value
            FROM
                #tbl_forum_data
                UNPIVOT (
                    value FOR DataPoint IN (
                        [JAN_Projected units],[JAN_Quantity units],[JAN_Parm Units  ],
                        [FEB_Projected units],[FEB_Quantity units],[FEB_Parm Units  ],
                        [MAR_Projected units],[MAR_Quantity units],[MAR_Parm Units  ]
                    )
                ) AS up_units
            UNION ALL
            SELECT
                Sno,[Month]=LEFT(DataPoint,3),category=SUBSTRING(DataPoint,5,LEN(DataPoint)),value
            FROM
                #tbl_forum_data
                UNPIVOT (
                    value FOR DataPoint IN (
                        [JAN_Projected value],[JAN_Quantity value],[JAN_Parm value  ],
                        [FEB_Projected value],[FEB_Quantity value],[FEB_Parm value  ],
                        [MAR_Projected value],[MAR_Quantity value],[MAR_Parm value  ]
                    )
                ) AS up_units
        ) AS up
    GROUP BY
        Sno,[Month]
    ORDER BY
        Sno,CASE [Month] WHEN 'JAN' THEN 0 WHEN 'FEB' THEN 1 ELSE 2 END;
    
    DROP TABLE #tbl_forum_data;
    

    1 和 2 的结果:

    +-----+-------+-----------------+-----------------+----------------+----------------+------------+------------+
    | Sno | Month | Projected units | Projected value | Quantity units | Quantity value | Parm Units | Parm Value |
    +-----+-------+-----------------+-----------------+----------------+----------------+------------+------------+
    |   1 | JAN   |               1 |               2 |              3 |              4 |          5 |          6 |
    |   1 | FEB   |               7 |               8 |              9 |             10 |         11 |         12 |
    |   1 | MAR   |              13 |              14 |             15 |             16 |         17 |         18 |
    +-----+-------+-----------------+-----------------+----------------+----------------+------------+------------+
    

    【讨论】:

    • 在不使用 union all 的情况下还有其他方法吗?
    • @KarthikVenkatraman 是的,但会更详细。如果你真的想比较,我可以打出来。
    • 基本上,当我使用 union all 时,我会感到内疚。如果我们使用 union all,执行计划的成本会更高。而且我还需要在 tableau 工作簿中使用这个 sql 代码来创建可视化,而我的查询又将在 tableau 中再次聚合。如果我在 tableau 中使用的查询更重,那么这对我来说将是个问题。所以我正在寻找一个不会花费很多执行成本的优化代码。另一件事是我有十二个月的数据。因此,使用 union all 为每个月复制相同的代码并没有那么大的可扩展性。如果我错了,请纠正我..
    • @KarthikVenkatraman UNPIVOT 的作用基本相同,为源集中的每一行生成若干行。这就是UNION ALLCROSS APPLY 中的用途。 Unpivot 将在屏幕后面执行此操作,您不会看到所有联合,但归结为相同。在某些情况下,使用交叉应用更方便。
    • @KarthikVenkatraman 更新了另一种编写查询的方式。
    猜你喜欢
    • 2019-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多