将行值转换为列值 SQL PIVOT

Making row values into column values SQL PIVOT

SQL Returns 以下结果来自 table

+-----+----+-----+----+----+
| PID | PY | QTY | TS | TM |
+-----+----+-----+----+----+
|  99 | CT |   1 |  1 |  6 |
|  99 | E  |   3 |  1 |  5 |
|  99 | GR |   4 |  1 |  6 |
+-----+----+-----+----+----+

我想使用 PIVOT(如果可能的话)使结果如下:

+-----+----+-----+----+----+----+------+------+------+------+------+------+------+
| PID | PY | QTY | TS | TM | PY | QTY  |  TS  |  TM  |  PY  | QTY  |  TS  |  TM  |
+-----+----+-----+----+----+----+------+------+------+------+------+------+------+
|  99 | CT |   1 |  1 |  6 | E    | 3    | 1    | 5    | GR   | 4    | 1    | 6    |
| 100 | V  |   6 |  6 |  2 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
+-----+----+-----+----+----+----+------+------+------+------+------+------+------+

如果您的值数量有限,那么获得结果的最简单方法是使用带有一些 CASE 表达式的聚合函数。

select 
  pid,
  PY1 = max(case when py = 'CT' then PY end),
  QTY1 = max(case when py = 'CT' then QTY else 0 end),
  TS1 = max(case when py = 'CT' then TS else 0 end),
  TM1 = max(case when py = 'CT' then TM else 0 end),
  PY2 = max(case when py = 'E' then PY end),
  QTY2 = max(case when py = 'E' then QTY else 0 end),
  TS2 = max(case when py = 'E' then TS else 0 end),
  TM2 = max(case when py = 'E' then TM else 0 end),
  PY3 = max(case when py = 'GR' then PY end),
  QTY3 = max(case when py = 'GR' then QTY else 0 end),
  TS3 = max(case when py = 'GR' then TS else 0 end),
  TM3 = max(case when py = 'GR' then TM else 0 end),
  PY4 = max(case when py = 'V' then PY end),
  QTY4 = max(case when py = 'V' then QTY else 0 end),
  TS4 = max(case when py = 'V' then TS else 0 end),
  TM4 = max(case when py = 'V' then TM else 0 end)
from yourtable
group by pid;

参见 SQL Fiddle with Demo。您可以使用 PIVOT 来获得结果,但它会更混乱,因为您需要先取消对多列的透视,然后再对它们进行透视。如果要使用数据透视功能,则必须执行以下操作。

首先,使用row_number()为每个pid组合分配一个唯一值:

select pid, py, qty, ts, tm,
  rn = row_number() over(partition by pid order by pid)
from yourtable

See Demo

然后逆透视多列 pyqtytstm:

select 
  pid, 
  new_col = col + cast(rn as varchar(10)),  
  val
from
(
  select pid, py, qty, ts, tm,
    rn = row_number() over(partition by pid order by pid)
  from yourtable
) d
cross apply
(
  select 'py', py union all
  select 'qty', cast(qty as varchar(10)) union all
  select 'ts', cast(ts as varchar(10)) union all
  select 'tm', cast(tm as varchar(10))
) c (col, val)

See Demo

我使用 CROSS APPLY 将多列转换为多行。最后,您将旋转 new_col 及其相应的值:

select pid,
    py1, qty1, ts1, tm1, py2, qty2, ts2, tm2,
    py3, qty3, ts3, tm3, py4, qty4, ts4, tm4
from
(
  select 
    pid, 
    new_col = col + cast(rn as varchar(10)),  
    val
  from
  (
    select pid, py, qty, ts, tm,
      rn = row_number() over(partition by pid order by pid)
    from yourtable
  ) d
  cross apply
  (
    select 'py', py union all
    select 'qty', cast(qty as varchar(10)) union all
    select 'ts', cast(ts as varchar(10)) union all
    select 'tm', cast(tm as varchar(10))
  ) c (col, val)
) src
pivot
(
    max(val)
    for new_col in (py1, qty1, ts1, tm1, py2, qty2, ts2, tm2,
                    py3, qty3, ts3, tm3, py4, qty4, ts4, tm4)
) piv;

See Demo

两个版本的最终结果相同。

| pid | py1 | qty1 | ts1 | tm1 | py2 | qty2 | ts2 | tm2 | py3 | qty3 | ts3 | tm3 |    py4 |   qty4 |    ts4 |    tm4 |
|-----|-----|------|-----|-----|-----|------|-----|-----|-----|------|-----|-----|--------|--------|--------|--------|
|  99 |  CT |    1 |   1 |   6 |   E |    3 |   1 |   5 |  GR |    4 |   1 |   6 | (null) | (null) | (null) | (null) |