2017-09-14 176 views
2

我在SQL Server中有一個凌亂的表(對不起,這是我從供應商那裏得到的)。我已經大大地減弱了它,這樣我就可以專注於這個問題,但我明顯失去了樹木的森林。Unpivot凌亂的表

客觀:排序這種數據,雖然我似乎無法得到正確的邏輯。
問題:奇怪的是,我需要列標題的子字符串作爲數據的一部分 - 正如您可以在下面的示例中看到的那樣。

Rextester樣本數據http://rextester.com/live/PHXT48379

我的表,一旦進口看起來像這樣:

+----+----------+--------------------+--------------------+-------------------+-------------------+ 
| id | person | contact 1 - phone | contact 2 - phone | contact 1 - email | contact 2 - email | 
+----+----------+--------------------+--------------------+-------------------+-------------------+ 
| 1 | john doe |    123456 |    234567 | [email protected]  | [email protected] | 
| 2 | jane doe |    654321 |    765432 | [email protected]  | NULL    | 
+----+----------+--------------------+--------------------+-------------------+-------------------+ 

預期輸出:

+----+----------+---------------+--------+-------------------+ 
| id | person | contactNumber | phone |  email  | 
+----+----------+---------------+--------+-------------------+ 
| 1 | John Doe |    1 | 123456 | [email protected]  | 
| 1 | John Doe |    2 | 234567 | [email protected] | 
| 2 | Jane Doe |    1 | 654321 | [email protected]  | 
| 2 | Jane Doe |    2 | 765432 | [email protected] | 
+----+----------+---------------+--------+-------------------+ 

回答

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,'[email protected]','[email protected]') 
,(2,'jane doe',654321,765432,'[email protected]',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

+0

我需要去動態 - 所以這似乎是有道理的。仍然需要消化這一點。我喜歡你的許多答案(已經發現一個公平的份額)都使用相同的工具 - 作爲XML,CROSS APPLY節點。 – Eli

+0

@Eli如您所知,SQL Server是按設計聲明的。您當然會使用經典的DYNAMIC SQL(這可能更具性能),但我喜歡XML方法的是沒有範圍問題,XML /源代碼可以是表格,視圖,甚至是具有派生列的自定義查詢。例如,我有一個Table-Value函數,它將幾乎任何選擇轉換爲EAV結構。作爲TVF,它可以合併到CROSS APPLY中或由另一個查詢使用。 –

+0

我試圖將你的概念實現到真實的數據集中,但是,我遇到了一些問題,其中「contactnumber」字段帶回了非數字值,並且他們打破了查詢失敗的轉換等。我添加了所有字段我不希望在第二個跨應用中「未插入」到「未插入」部分,但無濟於事:( – Eli

1

你可以只使用UNION生產用於接觸所有記錄1和聯繫人2的所有記錄,如果聯繫人2有或者電子郵件或電話不爲空。如果聯繫人2的電子郵件爲空,請使用COALESCE來使用聯繫人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 
+1

我想聯繫號碼2展現出來,但如果它不存在,我希望有一個NULL - COALESCE會再次給我第一個 - 我不想要那個。 – Eli

+0

好的。我改變了我的答案,以便電話將爲空。 –

+0

使用'COALESCE',它仍然顯示第一個聯繫人的電子郵件地址,如果第二個是'NULL' – Eli

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 
+0

您忘記了FROM子句 – Eli

+1

此外,它與我的答案基本相同。 –

+0

FROM子句添加 –