SQL Server 2012:解析XML然后选择一个子节点并连接所有子节点
SQL Server 2012: parse XML then pick one of subnodes as well as concat all sub nodes
我正在尝试解析 XML 列并尝试做两件事
- 遍历一个节点的多个子节点,根据1/0标志值选择一个节点。
- 合并所有子节点以创建一个合并字段(分隔)
可运行代码块 - SQL 服务器 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,主要 phone 是 (101)333-2222 而不是 null。
此外,位置应该是 "NY,DC" 而不仅仅是纽约。
如果您能为实现这一结果提供任何帮助,我将不胜感激。
谢谢
这应该可以解决问题:
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;
我的建议是在.nodes()
中使用XQuery
找到phone节点,也就是primary,XQuery
-function data()
为您的位置。此函数将 return 包含的所有文本部分都用空格分隔(顺便说一句:很奇怪,不能传入分隔符...)。在您的情况下,我希望 solid-two-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);
我正在尝试解析 XML 列并尝试做两件事
- 遍历一个节点的多个子节点,根据1/0标志值选择一个节点。
- 合并所有子节点以创建一个合并字段(分隔)
可运行代码块 - SQL 服务器 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,主要 phone 是 (101)333-2222 而不是 null。 此外,位置应该是 "NY,DC" 而不仅仅是纽约。
如果您能为实现这一结果提供任何帮助,我将不胜感激。 谢谢
这应该可以解决问题:
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;
我的建议是在.nodes()
中使用XQuery
找到phone节点,也就是primary,XQuery
-function data()
为您的位置。此函数将 return 包含的所有文本部分都用空格分隔(顺便说一句:很奇怪,不能传入分隔符...)。在您的情况下,我希望 solid-two-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);