使用SQL将非平衡多列转换为单列

时间:2012-11-14 12:13:11

标签: sql sql-server

我有一些结构不平衡的电子表格

    ID Date       Val Date       Val Date       Val
    1  2000/01/01 2   2000/12/31 1  
    2  1999/01/28 6   2001/02/01 5   2001/12/31 6
    ....

我想将其重新排列为以下内容

    ID Date       Val
    1  2000/01/01 2
    1  2000/12/31 1
    2  1999/01/28 6
    2  2001/02/01 5
    2  2001/12/31 6
    ....

请告诉我如何在MS SQL Server中执行此操作?谢谢!

样本数据:

    create table tmp
    (
        id smallint not null,
        date1 Date,
        val1 smallint,
        date2 date,
        val2 smallint,
        date3 date,
        val3 smallint
     );

     insert into tmp(id, date1, val1, date2, val2) values (1, '2001-01-01',5,'2001-12-31',6);
     insert into tmp(id, date1, val1, date2, val2, date3, val3) values (2, '1999-02-01',3,'2000-12-31',2, '2001-05-01',3);

     select * from tmp

    1   2001-01-01  5   2001-12-31  6   NULL    NULL
    2   1999-02-01  3   2000-12-31  2   2001-05-01  3

但是以下代码将返回

     select c.* from tmp cross apply 
    (
        select id, date1, val1 from tmp where date1 is not null
        union all
        select id, date2, val2 from tmp where date2 is not null
        union all
        select id, date3, val3 from tmp where date3 is not null
    ) 
     as c

    1   2001-01-01  5
    1   2001-01-01  5
    2   1999-02-01  3
    2   1999-02-01  3
    1   2001-12-31  6
    1   2001-12-31  6
    2   2000-12-31  2
    2   2000-12-31  2
    2   2001-05-01  3
    2   2001-05-01  3

1 个答案:

答案 0 :(得分:1)

从SQL Server 2005开始,您可以将函数/子查询应用于源数据集中的每一行。

SELECT
  normalised.*
FROM
  yourTable AS tmp
CROSS APPLY
(
  SELECT tmp.id, tmp.date1, tmp.val1 WHERE tmp.date1 IS NOT NULL
  UNION ALL
  SELECT tmp.id, tmp.date2, tmp.val2 WHERE tmp.date2 IS NOT NULL
  UNION ALL
  SELECT tmp.id, tmp.date3, tmp.val3 WHERE tmp.date3 IS NOT NULL
)
  AS normalised


在Sql Server 2005之前,您可以将三个单独的查询组合在一起。

  SELECT id, date1, val1 FROM yourTable WHERE date1 IS NOT NULL
  UNION ALL
  SELECT id, date2, val2 FROM yourTable WHERE date2 IS NOT NULL
  UNION ALL
  SELECT id, date3, val3 FROM yourTable WHERE date3 IS NOT NULL