Выберите значения из поля XML в SQL Server 2008
просто глядя на мое поле XML, мои строки выглядят так:
<person><firstName>Jon</firstName><lastName>Johnson</lastName></person>
<person><firstName>Kathy</firstName><lastName>Carter</lastName></person>
<person><firstName>Bob</firstName><lastName>Burns</lastName></person>
обратите внимание, что эти три строки в моей таблице.
Я хотел бы вернуть результат SQL в виде таблицы, как в
Jon | Johnson
Kathy| Carter
Bob | Burns
какой запрос будет выполнять это?
9 ответов:
учитывая, что поле XML называется 'xmlField'...
SELECT [xmlField].value('(/person//firstName/node())[1]', 'nvarchar(max)') as FirstName, [xmlField].value('(/person//lastName/node())[1]', 'nvarchar(max)') as LastName FROM [myTable]
учитывая, что XML-данные поступают из таблицы "таблица" и хранятся в столбце "поле": используйте методы XML, извлеките значения с помощью
xml.value(), узлов проекта сxml.nodes()используйтеCROSS APPLYприсоединиться к:SELECT p.value('(./firstName)[1]', 'VARCHAR(8000)') AS firstName, p.value('(./lastName)[1]', 'VARCHAR(8000)') AS lastName FROM table CROSS APPLY field.nodes('/person') t(p)вы можете бросить
nodes()иcross applyесли каждое поле содержит ровно один элемент "человек". Если XML-это переменная, которую вы выбираетеFROM @variable.nodes(...)и вам не нужноcross apply.
этот пост был полезен для решения моей проблемы, которая имеет немного другой формат XML... мой XML содержит список ключей, как в следующем примере, и я храню XML в столбце SourceKeys в таблице с именем DeleteBatch:
<k>1</k> <k>2</k> <k>3</k>создайте таблицу и заполните ее некоторыми данными:
CREATE TABLE dbo.DeleteBatch ( ExecutionKey INT PRIMARY KEY, SourceKeys XML) INSERT INTO dbo.DeleteBatch ( ExecutionKey, SourceKeys ) SELECT 1, (CAST('<k>1</k><k>2</k><k>3</k>' AS XML)) INSERT INTO dbo.DeleteBatch ( ExecutionKey, SourceKeys ) SELECT 2, (CAST('<k>100</k><k>101</k>' AS XML))вот мой SQL, чтобы выбрать ключи из XML:
SELECT ExecutionKey, p.value('.', 'int') AS [Key] FROM dbo.DeleteBatch CROSS APPLY SourceKeys.nodes('/k') t(p)вот результаты запроса...
ExecutionKey Key 1 1 1 2 1 3 2 100 2 101
Это может ответить на ваш вопрос:
select cast(xmlField as xml) xmlField into tmp from ( select '<person><firstName>Jon</firstName><lastName>Johnson</lastName></person>' xmlField union select '<person><firstName>Kathy</firstName><lastName>Carter</lastName></person>' union select '<person><firstName>Bob</firstName><lastName>Burns</lastName></person>' ) tb SELECT xmlField.value('(person/firstName)[1]', 'nvarchar(max)') as FirstName ,xmlField.value('(person/lastName)[1]', 'nvarchar(max)') as LastName FROM tmp drop table tmp
черт. Это был действительно полезный поток, чтобы обнаружить.
Я все еще нашел некоторые из этих предложений запутанными. Всякий раз, когда я использовал
valueС[1]в строке он будет извлекать только первое значение. И некоторые предложения рекомендуется использоватьcross apply, который (в моих тестах) просто привез слишком много данных.Итак, вот мой простой пример того, как вы создадите
xmlобъект, затем считывает его значения в таблицу.DECLARE @str nvarchar(2000) SET @str = '' SET @str = @str + '<users>' SET @str = @str + ' <user>' SET @str = @str + ' <firstName>Mike</firstName>' SET @str = @str + ' <lastName>Gledhill</lastName>' SET @str = @str + ' <age>31</age>' SET @str = @str + ' </user>' SET @str = @str + ' <user>' SET @str = @str + ' <firstName>Mark</firstName>' SET @str = @str + ' <lastName>Stevens</lastName>' SET @str = @str + ' <age>42</age>' SET @str = @str + ' </user>' SET @str = @str + ' <user>' SET @str = @str + ' <firstName>Sarah</firstName>' SET @str = @str + ' <lastName>Brown</lastName>' SET @str = @str + ' <age>23</age>' SET @str = @str + ' </user>' SET @str = @str + '</users>' DECLARE @xml xml SELECT @xml = CAST(CAST(@str AS VARBINARY(MAX)) AS XML) -- Iterate through each of the "users\user" records in our XML SELECT x.Rec.query('./firstName').value('.', 'nvarchar(2000)') AS 'FirstName', x.Rec.query('./lastName').value('.', 'nvarchar(2000)') AS 'LastName', x.Rec.query('./age').value('.', 'int') AS 'Age' FROM @xml.nodes('/users/user') as x(Rec)и вот вывод:
это странный синтаксис, но с достойным примером, это достаточно легко добавить к вашим собственным функциям SQL Server.
Кстати, вот правильно ответ на этот вопрос.
предполагая, что у вас есть ваши xml-данные в
@xmlпеременной типаxml(как показано в моем примере выше), вот как вы вернете три строки данных из xml, указанных в вопрос:SELECT x.Rec.query('./firstName').value('.', 'nvarchar(2000)') AS 'FirstName', x.Rec.query('./lastName').value('.', 'nvarchar(2000)') AS 'LastName' FROM @xml.nodes('/person') as x(Rec)
Если вы можете обернуть XML в корневой элемент-скажем, то следующее решение:
DECLARE @PersonsXml XML = '<persons><person><firstName>Jon</firstName><lastName>Johnson</lastName></person> <person><firstName>Kathy</firstName><lastName>Carter</lastName></person> <person><firstName>Bob</firstName><lastName>Burns</lastName></person></persons>' SELECT b.value('(./firstName/text())[1]','nvarchar(max)') as FirstName, b.value('(./lastName/text())[1]','nvarchar(max)') as LastName FROM @PersonsXml.nodes('/persons/person') AS a(b)
SELECT cast(xmlField as xml).value('(/person//firstName/node())[1]', 'nvarchar(max)') as FirstName, cast(xmlField as xml).value('(/person//lastName/node())[1]', 'nvarchar(max)') as LastName FROM [myTable]
/* В этом примере используется переменная XML со схемой * /
IF EXISTS (SELECT * FROM sys.xml_schema_collections WHERE name = 'OrderingAfternoonTea') BEGIN DROP XML SCHEMA COLLECTION dbo.OrderingAfternoonTea END GO CREATE XML SCHEMA COLLECTION dbo.OrderingAfternoonTea AS N'<?xml version="1.0" encoding="UTF-16" ?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://Tfor2.com/schemas/actions/orderAfternoonTea" xmlns="http://Tfor2.com/schemas/actions/orderAfternoonTea" xmlns:TFor2="http://Tfor2.com/schemas/actions/orderAfternoonTea" elementFormDefault="qualified" version="0.10" > <xsd:complexType name="AfternoonTeaOrderType"> <xsd:sequence> <xsd:element name="potsOfTea" type="xsd:int"/> <xsd:element name="cakes" type="xsd:int"/> <xsd:element name="fruitedSconesWithCream" type="xsd:int"/> <xsd:element name="jams" type="xsd:string"/> </xsd:sequence> <xsd:attribute name="schemaVersion" type="xsd:long" use="required"/> </xsd:complexType> <xsd:element name="afternoonTeaOrder" type="TFor2:AfternoonTeaOrderType"/> </xsd:schema>' ; GO DECLARE @potsOfTea int; DECLARE @cakes int; DECLARE @fruitedSconesWithCream int; DECLARE @jams nvarchar(128); DECLARE @RequestMsg NVARCHAR(2048); DECLARE @RequestXml XML(dbo.OrderingAfternoonTea); set @potsOfTea = 5; set @cakes = 7; set @fruitedSconesWithCream = 25; set @jams = N'medlar jelly, quince and mulberry'; SELECT @RequestMsg = N'<?xml version="1.0" encoding="utf-16" ?> <TFor2:afternoonTeaOrder schemaVersion="10" xmlns:TFor2="http://Tfor2.com/schemas/actions/orderAfternoonTea"> <TFor2:potsOfTea>' + CAST(@potsOfTea as NVARCHAR(20)) + '</TFor2:potsOfTea> <TFor2:cakes>' + CAST(@cakes as NVARCHAR(20)) + '</TFor2:cakes> <TFor2:fruitedSconesWithCream>' + CAST(@fruitedSconesWithCream as NVARCHAR(20)) + '</TFor2:fruitedSconesWithCream> <TFor2:jams>' + @jams + '</TFor2:jams> </TFor2:afternoonTeaOrder>'; SELECT @RequestXml = CAST(CAST(@RequestMsg AS VARBINARY(MAX)) AS XML) ; with xmlnamespaces('http://Tfor2.com/schemas/actions/orderAfternoonTea' as tea) select cast( x.Rec.value('.[1]/@schemaVersion','nvarchar(20)') as bigint ) as schemaVersion, cast( x.Rec.query('./tea:potsOfTea') .value('.','nvarchar(20)') as bigint ) as potsOfTea, cast( x.Rec.query('./tea:cakes') .value('.','nvarchar(20)') as bigint ) as cakes, cast( x.Rec.query('./tea:fruitedSconesWithCream') .value('.','nvarchar(20)') as bigint ) as fruitedSconesWithCream, x.Rec.query('./tea:jams').value('.','nvarchar(50)') as jams from @RequestXml.nodes('/tea:afternoonTeaOrder') as x(Rec); select @RequestXml.query('/*')
MSSQL использует обычные правила XPath следующим образом:
- nodename выбирает все узлы с именем "nodename"
- / выбирает из корневого узла
- / / выбирает узлы в документе из текущего узла, которые соответствуют выбору независимо от того, где они находятся
- . Выбирает текущий узел
- .. Выбирает родителя текущего узла
- @ выбирает атрибуты



Comments