TSQL:将XML嵌套标记提取到列中

时间:2013-04-23 14:47:39

标签: sql-server xml tsql

使用SQLServer2008R2

我目前有XML标签,其中包含XML标签内的数据(不在它们之间),例如:

<zooid="1"><animals key="all" zebras="22" dogs="0" birds="4" /><animals key="all" workers="yes" vacation="occasion" /> ... *(more)*</zooid>
<zooid="2"><animals key="house" zebras="0" dogs="1" birds="2" /><animals key="house" workers="no" vacation="no" /> ... *(more)*</zoodid>

如果我查询XML或对其使用值函数,它将返回空值,因为它尝试在标记之间读取 - 其中不存在值。我需要它来读取内部标签,将等号前的值解析为列,将引号之间的值解析为这些列中的值(授予,我可以创建一个可以执行此操作的函数,但这会非常细致,我很好奇这样的事情是否已经存在)。在

中应该是什么样子
Key | Zebras | Dogs | Birds | Key | Workers | Vacation | ... *(more)*

...这是数据行

all   | 22 | 0 | 4 | all   | yes | occasion | ... *(more)*
house | 0  | 1 | 2 | house | no  | no       | ... *(more)*

所以最后的输出(从现在开始只使用两个XML行),看起来就像表格中的以下数据一样:

Key   | Zebras | Dogs | Birds | Key    | Workers | Vacation | ... *(more)*
================================================================
all   | 22     | 0    | 4     | all   | yes     | occasion | ... *(more)*
house | 0      | 1    | 2     | house | no      | no       | ... *(more)*

除了查询XML,使用.query工具甚至尝试.node工具(使用CROSS APPLY请参阅this thread),我还无法生成此

2 个答案:

答案 0 :(得分:1)

您的xml似乎无效。你怎么能指定这样的元素:?通常xml结构是&lt;(elementName)(Attribute)=&#34;(Value)&#34; /&gt;。除非我错误地将你的文本转换为xml,否则它将失败。假设我可以在自动提取示例中显示正确xml的工作示例,该示例将在SQL Managment Studio中按原样运行。

declare @text1 varchar(max) = '<zooid="1"><animals="all" zebras="22" dogs="0" birds="4" /><animals="all" workers="yes" vacation="occasion" /></zooid>'
,   @text2 varchar(max) = '<a zooid="1"><b animals="all" zebras="22" dogs="0" birds="4" /><b animals="all" workers="yes" vacation="occasion" /></a>'
,   @xml xml
;

begin try 
    set @xml = cast(@text1 as xml)
end try
begin catch
    set @xml = '<ElementName Attribute="BadData Elements are not named" />'
end catch 

select @xml

begin try 
    set @xml = cast(@text2 as xml)
end try
begin catch
    set @xml = '<ElementName Attribute="BadData" />'
end catch 

select  
    @xml.value('(/a/b/@animals)[1]', 'varchar(20)') as AnimalsValue
,   @xml.value('(/a/b/@zebras)[1]', 'int') as ZebrasValue
,   @xml.value('(/a/b/@dogs)[1]', 'int') as DogsValue
,   @xml.value('(/a/b/@birds)[1]', 'int') as BirdsValue
,   @xml.value('(/a/b/@workers)[1]', 'varchar(16)') as Workers
,   @xml.value('(/a/b/@vacation)[1]', 'varchar(16)') as Vacation

&#39; .value&#39; method是在SQL中查询xml的语法。我基本上找到了元素(我做了包含b的泛型)。然后,一旦达到我想要的水平&#39; @ animals&#39;代表名称动物的属性&#39;。 [1]是一个位置,因为我一次只能返回一个东西,所以我选择了第一个位置。然后需要返回一个数据类型。文本是varchar,数字是整数。

XML查询方法:http://msdn.microsoft.com/en-us/library/ms190798.aspx

答案 1 :(得分:1)

试试这个 -

DECLARE @YourXML NVARCHAR(MAX)
SELECT @YourXML = '
    <zooid="1">
        <animals key="all" zebras="22" dogs="0" birds="4" />
        <animals key="all" workers="yes" vacation="occasion" />
    </zooid>
    <zooid="2">
        <animals key="house" zebras="0" dogs="1" birds="2" />
        <animals key="house" workers="no" vacation="no" />
    </zoodid>'

DECLARE @XML XML
SELECT @XML = 
    REPLACE(
          REPLACE(@YourXML, 'zooid=', 'zooid id=')
        , '</zoodid>'
        , '</zooid>')

SELECT 
      d.[Key]
    , Dogs = MAX(d.Dogs)
    , Zebras = MAX(d.Zebras)
    , Birds = MAX(d.Birds)
    , Workers = MAX(d.Workers)
    , Vacation = MAX(d.Vacation)
FROM (
    SELECT 
          [Key] = t.p.value('./@key', 'NVARCHAR(50)')
        , Zebras = t.p.value('./@zebras', 'INT')
        , Dogs = t.p.value('./@dogs', 'INT')
        , Birds = t.p.value('./@birds', 'INT')
        , Workers = t.p.value('./@workers', 'NVARCHAR(20)')
        , Vacation = t.p.value('./@vacation', 'NVARCHAR(20)')
    FROM @XML.nodes('/zooid/animals') t(p)
) d
GROUP BY d.[Key]