sql将行转置为列

时间:2013-09-04 16:14:59

标签: sql sql-server-2008-r2 pivot unpivot

假设我有下表:

+---------+------+-------------+-----+-------+--------+
| invoice | item | description | qty | price | amount |
+---------+------+-------------+-----+-------+--------+
|    1234 | L    | labour      |   1 |    50 |     50 |
|    1234 | P    | parts       |   2 |   100 |    200 |
|    9865 | L    | labour      |   1 |    25 |     25 |
|    9865 | P    | parts       |   1 |    25 |     25 |
|    5555 | P    | parts       |   2 |   100 |    200 |
+---------+------+-------------+-----+-------+--------+

我想要一个选择查询,它会将2行转置为每个唯一发票号的列,以便每个发票号只有一行。

所以对于上面的例子,我希望如下:

+---------+-------+--------------+------+--------+---------+-------+--------------+------+--------+---------+
| invoice | item1 | description1 | qty1 | price1 | amount1 | item2 | description2 | qty2 | price2 | amount2 |
+---------+-------+--------------+------+--------+---------+-------+--------------+------+--------+---------+
|    1234 | L     | labour       |    1 |     50 |      50 | P     | parts        | 2    | 100    | 200     |
|    9865 | L     | labour       |    1 |     25 |      25 | P     | parts        | 1    | 25     | 25      |
|    5555 | P     | parts        |    2 |    100 |     200 | NULL  | NULL         | NULL | NULL   | NULL    |
+---------+-------+--------------+------+--------+---------+-------+--------------+------+--------+---------+

注意我正在寻找静态/预定义数量的列,而不是基于订单项的动态。

1 个答案:

答案 0 :(得分:2)

如果要将有限数量的值转换为列,则可以使用带有CASE表达式和聚合函数的row_number()轻松完成此操作:

select invoice,
  max(case when seq = 1 then item end) item1,
  max(case when seq = 1 then description end) description1,
  max(case when seq = 1 then qty end) qty1,
  max(case when seq = 1 then price end) price1,
  max(case when seq = 1 then amount end) amount1,
  max(case when seq = 2 then item end) item2,
  max(case when seq = 2 then description end) description2,
  max(case when seq = 2 then qty end) qty2,
  max(case when seq = 2 then price end) price2,
  max(case when seq = 2 then amount end) amount2
from 
(
  select invoice, item, description, qty, price, amount,
    row_number() over(partition by invoice order by invoice) seq
  from yourtable
) d
group by invoice;

SQL Fiddle with Demo

但是如果您想使用PIVOT函数来获取结果,那么您需要查看多列的取消隐藏(itemdescriptionqtypriceamount)首先,然后应用数据透视功能。使用PIVOT的代码类似于:

;with cte as
(
  select invoice, item, description, qty, price, amount,
    row_number() over(partition by invoice order by invoice) seq
  from yourtable
)
select invoice,
  item1, description1, qty1, price1, amount1,
  item2, description2, qty2, price2, amount2
from
(
  select invoice, 
    col = col+cast(seq as varchar(10)), 
    value
  from cte
  cross apply
  (
    select 'item', item union all
    select 'description', description union all
    select 'qty', cast(qty as varchar(50)) union all
    select 'price', cast(price as varchar(50)) union all
    select 'amount', cast(amount as varchar(50))
  ) c (col, value)
) d
pivot
(
  max(value)
  for col in (item1, description1, qty1, price1, amount1,
              item2, description2, qty2, price2, amount2)
) piv;

SQL Fiddle with Demo。两者都会给出结果:

| INVOICE | ITEM1 | DESCRIPTION1 | QTY1 | PRICE1 | AMOUNT1 |  ITEM2 | DESCRIPTION2 |   QTY2 | PRICE2 | AMOUNT2 |
|    1234 |     L |       labour |    1 |     50 |      50 |      P |        parts |      2 |    100 |     200 |
|    5555 |     P |        parts |    2 |    100 |     200 | (null) |       (null) | (null) | (null) |  (null) |
|    9865 |     L |       labour |    1 |     25 |      25 |      P |        parts |      1 |     25 |      25 |