SQL Unpivot 多列数据

Posted

技术标签:

【中文标题】SQL Unpivot 多列数据【英文标题】:SQL Unpivot multiple columns Data 【发布时间】:2013-09-04 14:57:46 【问题描述】:

我使用的是 SQL Server 2008,我正在尝试对数据进行反透视。这是我正在使用的 SQL 代码,

CREATE TABLE #pvt1 (VendorID int, Sa int, Emp1 int,Sa1 int,Emp2 int)
GO
INSERT INTO #pvt1  VALUES (1,2,4,3,9);

GO

--Unpivot the table.
SELECT distinct VendorID,Orders,Orders1
FROM 
   (SELECT VendorID, Emp1, Sa,Emp2,Sa1
   FROM #pvt1 ) p
UNPIVOT
   (Orders FOR Emp IN 
      (Emp1,Emp2)
)AS unpvt
UNPIVOT
   (Orders1 FOR Emp1 IN 
      (Sa,Sa1)
)AS unpvt1;
GO

这是上面代码的结果。

VendorID    Orders  Orders1
1            4      2
1            4      3
1            9      2
1            9      3

但我希望我的输出如下所示

VendorID    Orders  Orders1
1           4       2
1           9       3

上面代码的关系是2与4相关,3与9相关。

我怎样才能做到这一点?

【问题讨论】:

FWIW .. 以下链接帮助了我... mangalpardeshi.blogspot.com/2009/04/… 【参考方案1】:

取消透视数据的更简单方法是使用 CROSS APPLY 成对取消透视列:

select vendorid, orders, orders1
from pvt1
cross apply
(
  select emp1, sa union all
  select emp2, sa1
) c (orders, orders1);

见SQL Fiddle with Demo。或者,如果您不想使用 UNION ALL,可以将 CROSS APPLY 与 VALUES 子句一起使用:

select vendorid, orders, orders1
from pvt1
cross apply
(
  values 
    (emp1, sa),
    (emp2, sa1)
) c (orders, orders1);

见SQL Fiddle with Demo

【讨论】:

哇...这非常有用,但我从来没有打扰过它。我需要尽快了解 CROSS APPLY。 这是非透视代码的绝佳替代品。我喜欢交叉申请!【参考方案2】:

Taryn 的回答确实超级有用,我想扩展它的一个方面。

如果您有一个像这样的非常未规范化的表,其中包含多组列,例如4 个季度或 12 个月:

+-------+------+------+------+------+------+------+-------+------+
| cYear | foo1 | foo2 | foo3 | foo4 | bar1 | bar2 | bar3  | bar4 |
+-------+------+------+------+------+------+------+-------+------+
|  2020 |   42 |  888 |    0 |   33 | one  | two  | three | four |
+-------+------+------+------+------+------+------+-------+------+

那么 CROSS APPLY 方法很容易编写和理解,当你掌握了它的窍门。对于编号列,使用常量值。

SELECT 
    cYear,
    cQuarter,
    foo,
    bar
FROM temp

CROSS APPLY
(
  VALUES
    (1, foo1, bar1),
    (2, foo2, bar2),
    (3, foo3, bar3),
    (4, foo4, bar4)

) c (cQuarter, foo, bar)

结果:

+-------+----------+-----+-------+
| cYear | cQuarter | foo |  bar  |
+-------+----------+-----+-------+
|  2020 |        1 |  42 | one   |
|  2020 |        2 | 888 | two   |
|  2020 |        3 |   0 | three |
|  2020 |        4 |  33 | four  |
+-------+----------+-----+-------+

SQL Fiddle

【讨论】:

【参考方案3】:

我需要复合键并跳过额外行以防数据丢失(NULL)。例如。当 x2 和 y2 是可能的替代供应商和价格时

WITH pvt AS (SELECT * FROM (VALUES 
   ( 1, 6, 11, 111, 12, 13, 122, 133),
   ( 2, 6, 21, 211, 22, 23, 222, 233),
   ( 3, 6, 31, 311, 32, 33, 322, 333),
   ( 5, 4, 41, 411, 42, NULL, 422, NULL),
   ( 6, 4, 51, 511, 52, NULL, 522, NULL))
   s( id, s, a, b, x1, x2, y1, y2)
)
-- SELECT * FROM pvt

SELECT CONCAT('xy_',s,'_', id, postfix) as comp_id, a, b, x, y 
FROM pvt
CROSS APPLY
(
  VALUES
    (NULL, x1, y1),   
    ('_ext', x2, y2)

) c (postfix, x, y)
WHERE x IS NOT NULL

生产

comp_id                          a           b           x           y
-------------------------------- ----------- ----------- ----------- -----------
xy_6_1                           11          111         12          122
xy_6_1_ext                       11          111         13          133
xy_6_2                           21          211         22          222
xy_6_2_ext                       21          211         23          233
xy_6_3                           31          311         32          322
xy_6_3_ext                       31          311         33          333
xy_4_5                           41          411         42          422
xy_4_6                           51          511         52          522

(8 rows affected)

来自:

id          s           a           b           x1          x2          y1          y2
----------- ----------- ----------- ----------- ----------- ----------- ----------- -----------
1           6           11          111         12          13          122         133
2           6           21          211         22          23          222         233
3           6           31          311         32          33          322         333
5           4           41          411         42          NULL        422         NULL
6           4           51          511         52          NULL        522         NULL

(受影响的 5 行)

【讨论】:

请用一个独立的陈述来介绍您的答案“或者可能是”正在提出替代解决方案,但与什么相反?你指的是另一个答案吗?原来的问题?

以上是关于SQL Unpivot 多列数据的主要内容,如果未能解决你的问题,请参考以下文章

PIVOT/UNPIVOT 多行多列

如何对具有常量/缺失列的多列使用 unpivot?

oracle unpivot 多列到多列

UnPivot 多列 MSSQLServer

多列,多表列到行 unpivot

oracle 多列 列转行