2016-11-28 56 views
1

我試圖解析XML列,並試圖通過節點的多個子節點做兩件事情的SQL Server 2012:解析XML,然後挑選一個子節點以及CONCAT所有子節點

  • 迭代,並挑選一個節點基於1/0標誌值。
  • 將所有的子節點創建一個組合場(分隔)

運行的代碼塊 - SQL Server 2012中:

create table #temp (XMLData xml) 

insert into #temp (XMLData) 
values (' 
<Report_Data> 
    <Report_Entry> 
    <IsActive>1</IsActive> 
    <PID>111</PID> 
    <Languages> 
     <Language>German</Language> 
     <speak>Y</speak> 
     <read>Y</read> 
     <write>Y</write> 
    </Languages> 
    <Languages> 
     <Language>Spanish</Language> 
     <speak>Y</speak> 
     <read>N</read> 
     <write>N</write> 
    </Languages> 
    <phone> 
     <PhoneNumber>(101)111-1111</PhoneNumber> 
     <PhoneType>Work</PhoneType> 
     <IsPrimary>1</IsPrimary> 
    </phone> 
    <phone> 
     <PhoneNumber>(101)111-2222</PhoneNumber> 
     <PhoneType>Mobile</PhoneType> 
     <IsPrimary>0</IsPrimary> 
    </phone> 
    </Report_Entry> 
    <Report_Entry> 
    <IsActive>1</IsActive> 
    <PID>222</PID> 
    <phone> 
     <PhoneNumber>(101)222-1111</PhoneNumber> 
     <PhoneType>Mobile</PhoneType> 
     <IsPrimary>0</IsPrimary> 
    </phone> 
    </Report_Entry> 
    <Report_Entry> 
    <IsActive>1</IsActive> 
    <PID>333</PID> 
    <phone> 
     <PhoneNumber>(101)333-1111</PhoneNumber> 
     <PhoneType>Phone</PhoneType> 
     <IsPrimary>0</IsPrimary> 
    </phone> 
    <phone> 
     <PhoneNumber>(101)333-2222</PhoneNumber> 
     <PhoneType>Mobile</PhoneType> 
     <IsPrimary>1</IsPrimary> 
    </phone> 
    <location> 
     <location-state>NY</location-state> 
    </location> 
    <location> 
     <location-state>DC</location-state> 
    </location> 
    </Report_Entry> 
</Report_Data> 
') 

select 
     c.value('IsActive[1]','varchar(1)') as IsActive 
    , c.value('PID[1]','varchar(5)') as PID 
    , case when c.value('phone[1]/IsPrimary[1]','int') = 1 then c.value('phone[1]/PhoneNumber[1]','varchar(15)') end as PublicWorkPhone /** this condition needs to look at all sub nodes. this stops at the first one. **/ 
    , c.value('location[1]','varchar(2)') as location 
from 
    #temp 
    cross apply #temp.XMLData.nodes('/Report_Data/Report_Entry') as y(c) 

drop table #temp 
GO 

我得到這個:

IsActive PID PublicWorkPhone location 
-------- ----- --------------- -------- 
1  111 (101)111-1111 NULL 
1  222 NULL   NULL 
1  333 NULL   NY 

然而,我需要這個:

IsActive PID PublicWorkPhone location 
-------- ----- --------------- -------- 
1  111 (101)111-1111 NULL 
1  222 NULL   NULL 
1  333 (101)333-2222 NY,DC 

對於PID = 333,主電話爲(101)333-2222,不爲空。 此外,位置應該是「紐約,特區」不只是紐約。

我真的很感謝任何幫助你可以提供實現的結果。 謝謝

+0

這是一個很好的問題:Copy'n'pasteable測試場景,自己的努力,錯誤的輸出,預期輸出。 +1從我身邊 – Shnugo

+0

@Shnugo,謝謝! – sch

回答

0

這應該做的伎倆:

WITH prep AS 
(
    SELECT 
    c.value('(IsActive[1]/text())[1]','char(1)') as IsActive, 
    c.value('(PID[1]/text())[1]','varchar(5)') as PID, 
    c.value('(phone[IsPrimary=1]/PhoneNumber/text())[1]', 'varchar(15)') AS PublicWorkPhone, 
    location = cc.value('(text())[1]', 'varchar(1000)') 
    from #temp 
    CROSS APPLY #temp.XMLData.nodes('/Report_Data/Report_Entry') as y(c) 
    OUTER APPLY c.nodes('location/location-state') AS z(cc) 
) 
SELECT 
    IsActive, 
    PID, 
    PublicWorkPhone, 
    Location = 
    STUFF ((
    SELECT ',' + location 
    FROM prep pp 
    WHERE p.PID = pp.PID 
    FOR XML PATH('')),1,1,'') 
FROM prep p 
GROUP BY IsActive, PID, PublicWorkPhone; 
+0

感謝您的解決方案。這對我來說確實有效。 – sch

1

我的建議使用在.nodes()XQuery找到電話節點,這是主要XQuery -function data()爲您的位置。這個函數將返回所有包含空白的文本部分(順便說一句:奇怪的是,無法通過分隔符char ...)。在你的情況下,我期望固二字符位置代碼。只需用逗號替換空白,這就是它......

SELECT re.value(N'IsActive[1]','bit') AS IsActive 
     ,re.value(N'PID[1]','int') AS PID 
     ,ph.value(N'PhoneNumber[1]','nvarchar(max)') AS PublicWorkPhone 
     ,REPLACE(re.query(N'data(location/location-state)').value('.','nvarchar(max)'),' ',',') AS location 
FROM #temp AS tmp 
CROSS APPLY tmp.XMLData.nodes(N'/Report_Data/Report_Entry') AS A(re) 
OUTER APPLY re.nodes(N'phone[IsPrimary=1]') AS B(ph); 
+0

感謝您幫助我的請求。我會用你的替代邏輯來獲得紐約,特區。這樣我只用一張桌子工作。 – sch

+0

@sch我不太明白,你的*你的方式*我只用一張桌子工作*實際上意味着,但我很高興,你找到了解決方案!請允許我提示一句:SO說話的方式*謝謝*是投票和接受。你接受了另一個答案。這非常好,完全取決於你。既然你已經越過了15個代表點邊界,你還可以投票。投票被計算爲徽章和特權。 – Shnugo

+0

我投了你的答案。我接受了另一個解決方案,因爲它解決了我現在的問題。當電話不可用時,它返回'NULL值IsActive PID公共工作電話位置' '-------- ----- --------------- --- ------'' 1 111 (101)111-1111 NULL' '1 222 NULL NULL' '1 333 (101)333-2222 NY,DC' VS 'IsActive PID PublicWorkPhone位置' '-------- ----- --------------- ---------' '1 111(101)111- 1111' '1 222 NULL' '1 333 (101)333-2222 NY,DC' – sch

相關問題