在 SQL Server 2008 中使用 Unpivot 或 Cross Apply 规范化数据

Posted

技术标签:

【中文标题】在 SQL Server 2008 中使用 Unpivot 或 Cross Apply 规范化数据【英文标题】:Normalizing data using Unpivot or Cross Apply in SQL Server 2008 【发布时间】:2014-09-03 20:40:09 【问题描述】:

我无法还原某些数据。我在这里看到了其他用于取消透视表的示例,但我有需要取消透视表的对。我的数据集中实际上有 10 多个疾病/日期对,但我选择了三对来简化示例。

这是我的源数据:

MRN      GUMCID     Event    BreastID  BreastDate  ColonID ColonDate    PancID  PancDate
2000012  90000001   event_1  42        1/1/2000    43      8/5/2014     44      8/6/2012
2008006  90000020   event_1  102       5/7/2003    103     9/11/2012        
2000012  90002002   event_1  900       8/5/2004    902     12/5/2009
2000012  90002002   event_2  1000      9/6/2006             

这是我需要将其转换为的内容

MRN     GUMCID    Event     TissueType  Date        ID
2000012 90000001  event_1   BreastID    1/1/2000    42
2000012 90000001  event_1   ColonID     8/5/2014    43
2000012 90000001  event_1   PancID      8/6/2012    44
2008006 90000020  event_1   BreastID    5/7/2003    102
2008006 90000020  event_1   ColonID     9/11/2012   103
2000012 90002002  event_1   BreastID    8/5/2004    900
2000012 90002002  event_1   PancID      12/5/2009   902
2000012 90002002  event_2   BreastID    9/6/2006    1000

我摸索过 unpivot 和 cross apply ,但似乎无法完成这项工作。任何想法表示赞赏!

【问题讨论】:

pancid 的日期从何而来? 它在源数据示例中,您必须向右滚动才能看到它。它位于 PancDate 列中。 啊抱歉手机浏览器不显示滚动条 【参考方案1】:

测试数据

DECLARE @TABLE TABLE 
(MRN INT, GUMCID INT, [Event] VARCHAR(10), BreastID INT, 
          BreastDate DATE, ColonID INT,  ColonDate DATE, PancID INT, PancDate DATE)
INSERT INTO @TABLE VALUES
(2000012,  90000001,'event_1',  42   ,'1/1/2000', 43  ,'8/5/2014' , 44 ,'8/6/2012'),
(2008006,  90000020,'event_1',  102  ,'5/7/2003', 103 ,'9/11/2012', NULL, NULL),       
(2000012,  90002002,'event_1',  900  ,'8/5/2004', 902 ,'12/5/2009', NULL, NULL),
(2000012,  90002002,'event_2',  1000 ,'9/6/2006', NULL, NULL      , NULL, NULL)

查询

SELECT MRN
      ,GUMCID
      ,[Event]
      ,TissueType
      ,CONVERT(VARCHAR(10),
                  CASE 
                        WHEN TissueType = 'BreastID' THEN BreastDate
                        WHEN TissueType = 'ColonID'  THEN ColonDate
                        WHEN TissueType = 'PancID'   THEN PancDate
                   END, 103)   AS [Date]     
      ,ID
FROM @Table t
 UNPIVOT (ID FOR TissueType IN (BreastID, ColonID, PancID)
          )up

结果

╔═════════╦══════════╦═════════╦════════════╦════════════╦══════╗
║   MRN   ║  GUMCID  ║  Event  ║ TissueType ║    Date    ║  ID  ║
╠═════════╬══════════╬═════════╬════════════╬════════════╬══════╣
║ 2000012 ║ 90000001 ║ event_1 ║ BreastID   ║ 01/01/2000 ║   42 ║
║ 2000012 ║ 90000001 ║ event_1 ║ ColonID    ║ 05/08/2014 ║   43 ║
║ 2000012 ║ 90000001 ║ event_1 ║ PancID     ║ 06/08/2012 ║   44 ║
║ 2008006 ║ 90000020 ║ event_1 ║ BreastID   ║ 07/05/2003 ║  102 ║
║ 2008006 ║ 90000020 ║ event_1 ║ ColonID    ║ 11/09/2012 ║  103 ║
║ 2000012 ║ 90002002 ║ event_1 ║ BreastID   ║ 05/08/2004 ║  900 ║
║ 2000012 ║ 90002002 ║ event_1 ║ ColonID    ║ 05/12/2009 ║  902 ║
║ 2000012 ║ 90002002 ║ event_2 ║ BreastID   ║ 06/09/2006 ║ 1000 ║
╚═════════╩══════════╩═════════╩════════════╩════════════╩══════╝

【讨论】:

谢谢!有没有一种简单的方法来提取 BreastID/ColonID/PancID 列名称以用作此处的 TissueType 值,而不是对它们进行硬编码?【参考方案2】:
select mrd, gumcid, event, tissuetype, date, id
from tbl
cross apply (
    values 
        ('breastid', breastid, breastdate),
        ('colonid', colonid, colondate),
        ('pancid', pancid, pancdate)
) t(tissuetype, id, date)
where id is not null

【讨论】:

谢谢!有没有一种简单的方法来提取 BreastID/ColonID/PancID 列名称以用作此处的 TissueType 值,而不是对它们进行硬编码?

以上是关于在 SQL Server 2008 中使用 Unpivot 或 Cross Apply 规范化数据的主要内容,如果未能解决你的问题,请参考以下文章

在 SQL Server 2008 中使用休眠

Query (SQL Server 2008 Express) 在 SQL Server Management Studio 中有效,但在 Delphi 中使用 ADODB 无效

在 sql server 2008 中使用 unicode 文本

安装SQL SERVER 2008,出现“查找sql server 2008安装媒体”的问题

在 SQL Server 2008 的拆分函数中使用连接表列

如何在 sql server 2008 的 exec 语句中使用替换