Sql 选择XML节点作为行
我正在使用T-SQL从具有XML列的表中进行选择。我想选择一个特定类型的节点,并为每个节点创建一行 例如,假设我正在从人员表中进行选择。此表有一个用于地址的XML列。XML的格式类似于以下内容:Sql 选择XML节点作为行,sql,xml,tsql,xpath,Sql,Xml,Tsql,Xpath,我正在使用T-SQL从具有XML列的表中进行选择。我想选择一个特定类型的节点,并为每个节点创建一行 例如,假设我正在从人员表中进行选择。此表有一个用于地址的XML列。XML的格式类似于以下内容: <address> <street>Street 1</street> <city>City 1</city> <state>State 1</state> <zipcode>Zip Code
<address>
<street>Street 1</street>
<city>City 1</city>
<state>State 1</state>
<zipcode>Zip Code 1</zipcode>
</address>
<address>
<street>Street 2</street>
<city>City 2</city>
<state>State 2</state>
<zipcode>Zip Code 2</zipcode>
</address>
我怎样才能得到这样的结果:
名称系统状态
乔·贝克尔·西塔特瓦
乔·贝克尔·塔科马瓦
Fred JonesVancouverBC如果您可以使用它,linq api对于XML非常方便:
var addresses = dataContext.People.Addresses
.Elements("address")
.Select(address => new {
street = address.Element("street").Value,
city = address.Element("city").Value,
state = address.Element("state").Value,
zipcode = address.Element("zipcode").Value,
});
以下是您的解决方案:
/* TEST TABLE */
DECLARE @PEOPLE AS TABLE ([Name] VARCHAR(20), [Address] XML )
INSERT INTO @PEOPLE SELECT
'Joel',
'<address>
<street>Street 1</street>
<city>City 1</city>
<state>State 1</state>
<zipcode>Zip Code 1</zipcode>
</address>
<address>
<street>Street 2</street>
<city>City 2</city>
<state>State 2</state>
<zipcode>Zip Code 2</zipcode>
</address>'
UNION ALL SELECT
'Kim',
'<address>
<street>Street 3</street>
<city>City 3</city>
<state>State 3</state>
<zipcode>Zip Code 3</zipcode>
</address>'
SELECT * FROM @PEOPLE
-- BUILD XML
DECLARE @x XML
SELECT @x =
( SELECT
[Name]
, [Address].query('
for $a in //address
return <address
street="{$a/street}"
city="{$a/city}"
state="{$a/state}"
zipcode="{$a/zipcode}"
/>
')
FROM @PEOPLE AS people
FOR XML AUTO
)
-- RESULTS
SELECT [Name] = T.Item.value('../@Name', 'varchar(20)'),
street = T.Item.value('@street' , 'varchar(20)'),
city = T.Item.value('@city' , 'varchar(20)'),
state = T.Item.value('@state' , 'varchar(20)'),
zipcode = T.Item.value('@zipcode', 'varchar(20)')
FROM @x.nodes('//people/address') AS T(Item)
/* OUTPUT*/
Name | street | city | state | zipcode
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Joel | Street 1 | City 1 | State 1 | Zip Code 1
Joel | Street 2 | City 2 | State 2 | Zip Code 2
Kim | Street 3 | City 3 | State 3 | Zip Code 3
我一般是这样做的: 我通过如下调用分解源XML
DECLARE @xmlEntityList xml
SET @xmlEntityList =
'
<ArbitrarilyNamedXmlListElement>
<ArbitrarilyNamedXmlItemElement><SomeVeryImportantInteger>1</SomeVeryImportantInteger></ArbitrarilyNamedXmlItemElement>
<ArbitrarilyNamedXmlItemElement><SomeVeryImportantInteger>2</SomeVeryImportantInteger></ArbitrarilyNamedXmlItemElement>
<ArbitrarilyNamedXmlItemElement><SomeVeryImportantInteger>3</SomeVeryImportantInteger></ArbitrarilyNamedXmlItemElement>
</ArbitrarilyNamedXmlListElement>
'
DECLARE @tblEntityList TABLE(
SomeVeryImportantInteger int
)
INSERT @tblEntityList(SomeVeryImportantInteger)
SELECT
XmlItem.query('//SomeVeryImportantInteger[1]').value('.','int') as SomeVeryImportantInteger
FROM
[dbo].[tvfShredGetOneColumnedTableOfXmlItems] (@xmlEntityList)
利用标量值函数
/* Example Inputs */
/*
DECLARE @xmlListFormat xml
SET @xmlListFormat =
'
<ArbitrarilyNamedXmlListElement>
<ArbitrarilyNamedXmlItemElement>004421UB7</ArbitrarilyNamedXmlItemElement>
<ArbitrarilyNamedXmlItemElement>59020UH24</ArbitrarilyNamedXmlItemElement>
<ArbitrarilyNamedXmlItemElement>542514NA8</ArbitrarilyNamedXmlItemElement>
</ArbitrarilyNamedXmlListElement>
'
declare @tblResults TABLE
(
XmlItem xml
)
*/
-- =============================================
-- Author: 6eorge Jetson
-- Create date: 01/02/3003
-- Description: Shreds a list of XML items conforming to
-- the expected generic @xmlListFormat
-- =============================================
CREATE FUNCTION [dbo].[tvfShredGetOneColumnedTableOfXmlItems]
(
-- Add the parameters for the function here
@xmlListFormat xml
)
RETURNS
@tblResults TABLE
(
-- Add the column definitions for the TABLE variable here
XmlItem xml
)
AS
BEGIN
-- Fill the table variable with the rows for your result set
INSERT @tblResults
SELECT
tblShredded.colXmlItem.query('.') as XmlItem
FROM
@xmlListFormat.nodes('/child::*/child::*') as tblShredded(colXmlItem)
RETURN
END
--SELECT * FROM @tblResults
如果这对其他正在寻找通用解决方案的人有用,我创建了一个CLR过程,它可以像上面一样获取Xml片段并将其分解成一个表格结果集,而无需提供关于列名称或类型的任何附加信息,也无需以任何方式自定义对给定Xml片段的调用:
当然也有一些限制xml必须是表格式的,就像这个示例一样,第一行需要包含所有支持的元素/列,等等,但我确实希望它比可用的内置内容提前几步。这里有一个替代解决方案:
;with cte as
(
select id, name, addresses, addresses.value('count(/address/city)','int') cnt
from @demo
)
, cte2 as
(
select id, name, addresses, addresses.value('((/address/city)[sql:column("cnt")])[1]','nvarchar(256)') city, cnt-1 idx
from cte
where cnt > 0
union all
select cte.id, cte.name, cte.addresses, cte.addresses.value('((/address/city)[sql:column("cte2.idx")])[1]','nvarchar(256)'), cte2.idx-1
from cte2
inner join cte on cte.id = cte2.id and cte2.idx > 0
)
select id, name, city
from cte2
order by id, city
仅供参考:我在这里的代码审查网站上发布了此SQL的另一个版本:我知道,但linq呈现给t-SQL。我猜这是一个存储过程。实际上是一个报表,但是的,我不能使用C。搜索了一会儿,直到我找到了这个优秀的示例。谢谢你!