Unpivot凌乱的桌子

时间:2017-09-14 19:18:41

标签: sql-server

我在SQL Server中有一个混乱的表(对不起,这是我从供应商那里得到它的方式)。我已经大大减少了它,所以我可以专注于这个问题,虽然我显然已经看不到森林的树木了。

目标:对这些数据进行UNPIVOT,但我似乎无法正确理解逻辑。
问题:怪癖是我需要列标题的子字符串作为数据的一部分 - 如下面的示例所示。

Rextester示例数据ggeffects-package

我的表,一旦导入就像这样:

+----+----------+--------------------+--------------------+-------------------+-------------------+
| id |  person  | contact 1 - phone  | contact 2 - phone  | contact 1 - email | contact 2 - email |
+----+----------+--------------------+--------------------+-------------------+-------------------+
|  1 | john doe |             123456 |             234567 | john@doe.me       | johndoe@gmail.com |
|  2 | jane doe |             654321 |             765432 | Jane@doe.me       | NULL              |
+----+----------+--------------------+--------------------+-------------------+-------------------+

预期输出:

+----+----------+---------------+--------+-------------------+
| id |  person  | contactNumber | phone  |       email       |
+----+----------+---------------+--------+-------------------+
|  1 | John Doe |             1 | 123456 | john@doe.me       |
|  1 | John Doe |             2 | 234567 | johndoe@gmail.com |
|  2 | Jane Doe |             1 | 654321 | jane@doe.me       |
|  2 | Jane Doe |             2 | 765432 | janedoe@gmail.com |
+----+----------+---------------+--------+-------------------+

3 个答案:

答案 0 :(得分:2)

万一你需要去"动态"从某种意义上说,你不知道列(或联系人)可能如何

示例

Declare @YourTable Table ([id] varchar(50),[person] varchar(50),[contact 1 - phone] varchar(50),[contact 2 - phone] varchar(50),[contact 1 - email] varchar(50),[contact 2 - email] varchar(50))
Insert Into @YourTable Values 
 (1,'john doe',123456,234567,'john@doe.me','johndoe@gmail.com')
,(2,'jane doe',654321,765432,'Jane@doe.me',NULL)


Select id
      ,person
      ,contactNumber
      ,phone  = max(case when Item like '%phone%' then value end)
      ,email  = max(case when Item like '%email%' then value end)
 From (
        Select A.ID
              ,A.Person
              ,contactNumber = cast(substring(Item,patindex('%[0-9]%',item),2) as int)
              ,C.*
         From @YourTable A
         Cross Apply ( values (cast((Select A.* for XML RAW) as xml))) B(XMLData)
         Cross Apply (
                        Select Item  = replace(a.value('local-name(.)','varchar(100)'),'_x0020_',' ')
                              ,Value = a.value('.','varchar(max)') 
                         From  B.XMLData.nodes('/row')  as C1(n)
                         Cross Apply C1.n.nodes('./@*') as C2(a)
                         Where a.value('local-name(.)','varchar(100)') not in ('id','person')
                     ) C
      )  A
 Group By id,person,contactNumber

<强>返回

enter image description here

  

编辑 - 简化

Select A.ID
      ,A.Person
      ,C.*
 From  @YourTable A
 Cross Apply ( values (cast((Select A.* for XML RAW) as xml))) B(XMLData)
 Cross Apply (
                Select Item  = replace(a.value('local-name(.)','varchar(100)'),'_x0020_',' ')
                      ,Value = a.value('.','varchar(max)') 
                 From  B.XMLData.nodes('/row')  as C1(n)
                 Cross Apply C1.n.nodes('./@*') as C2(a)
                 Where a.value('local-name(.)','varchar(100)') not in ('id','person')
             ) C

返回

enter image description here

答案 1 :(得分:1)

如果联系人2或者电子邮件或电话不为空,您可以使用UNION生成联系人1的所有记录和联系人2的所有记录。如果contact-2的电子邮件为空,请使用COALESCE来使用contact-1的电子邮件。

SELECT id, person, 1 [contactNumber], [contact 1 - phone] [phone], [contact 1 - email] [email]
FROM #TEST

UNION

SELECT id, person, 2
  , [contact 2 - phone]
  , COALESCE([contact 2 - email], [contact 1 - email])
FROM #TEST
WHERE [contact 2 - phone] IS NOT NULL OR [contact 2 - email] IS NOT NULL

答案 2 :(得分:1)

你试过这个吗?

SELECT 
    id, 
    person,
    1 as contactnumber, 
    [contact 1 - phone] as phone, 
    [contact 1 - email] as email 
FROM Table
UNION
SELECT 
    id, 
    person,
    2 as contactnumber, 
    [contact 2 - phone] as phone, 
    [contact 2 - email] as email 
FROM Table