使用SQL Server将XML解析为列

使用SQL Server将XML解析为列,sql,sql-server,xml,xpath,sqlxml,Sql,Sql Server,Xml,Xpath,Sqlxml,使用SQL Server将XML解析为列的最简单方法是什么。例如: <ns0:root xmlns:ns0="http://herp..."> <ns1:FirstElement xmlns:ns1="http://derpyderp..."> <ns1:FirstElementID>AAF11303</ns1:FirstElementID> <ns1:FirstEValue>some rando

使用SQL Server将XML解析为列的最简单方法是什么。例如:

<ns0:root xmlns:ns0="http://herp...">
    <ns1:FirstElement xmlns:ns1="http://derpyderp...">
        <ns1:FirstElementID>AAF11303</ns1:FirstElementID>
        <ns1:FirstEValue>some random text</ns1:FirstEValue>
        <ns1:SecondElement>
            <ns1:Something>Asdsad</ns1:Something>
            <ns1:Else>
                <ns1:Stuff>sdf</ns1:Stuff>
                <ns1:StuffVal>15</ns1:StuffVal>
            </ns1:Else>
            <ns1:Else>
                <ns1:Stuff>jarjar</ns1:Stuff>
                <ns1:StuffVal>16</ns1:StuffVal>
                <ns1:StuffParam>true</ns1:StuffParam>
            </ns1:Else>
        </ns1:SecondElement>
        <ns1:randValue>dosd</ns1:randValue>
    </ns1:FirstElement>
    <ns1:FirstElement>
        <ns1:FirstElementID>DDF00301</ns1:FirstElementID>
        <ns1:FirstEValue/>
        <ns1:SecondElement>
            <ns1:Else>
                <ns1:Stuff>yessir</ns1:Stuff>
                <ns1:StuffVal>0</ns1:StuffVal>
            </ns1:Else>
        </ns1:SecondElement>        
    </ns1:FirstElement>
    <!-- ... times n the first element with a variating amount of children up to 15 levels deep -->
</ns0:root>
现在,实际的XML要复杂得多,到目前为止,我看到的所有示例都涉及到手动解析XML,基本上是将每个子元素作为自己的XML传递,并在脚本的下一个循环中分别解析

有没有办法直接输出这样的值?手动解析数MB的XML,其中有无数的元素出现,以及出现的次数和位置,这将需要一天的操作

我一直在考虑用C#编写一个CLR程序集,并将结果作为一个表传递到SQL中,但我想知道是否还有其他相同的方法

谢谢

基本上,您可以使用和方法解析xml(并处理名称空间)。大概是这样的:

;with xmlnamespaces('http://herp...' as ns0, 'http://derpyderp...' as ns1)
select
    T.C.value('(../../ns1:FirstElementID/text())[1]', 'nvarchar(max)') as FirstElementID,
    T.C.value('(../../ns1:FirstEValue/text())[1]', 'nvarchar(max)') as FirstEValue,
    T.C.value('(../ns1:Something/text())[1]', 'nvarchar(max)') as Something,
    T.C.value('(ns1:Stuff/text())[1]', 'nvarchar(max)') as [Else.Stuff],
    T.C.value('(ns1:StuffVal/text())[1]', 'nvarchar(max)') as [Else.StuffVal],
    T.C.value('(ns1:StuffParam/text())[1]', 'nvarchar(max)') as [Else.StuffParam],
    T.C.value('(../../ns1:randValue/text())[1]', 'nvarchar(max)') as [randValue]
from @data.nodes('ns0:root/ns1:FirstElement/ns1:SecondElement/ns1:Else') as T(C)
;with xmlnamespaces('http://herp...' as ns0, 'http://derpyderp...' as ns1)
select
    F.C.value('(ns1:FirstElementID/text())[1]', 'nvarchar(max)') as FirstElementID,
    F.C.value('(ns1:FirstEValue/text())[1]', 'nvarchar(max)') as FirstEValue,
    S.C.value('(ns1:Something/text())[1]', 'nvarchar(max)') as Something,
    E.C.value('(ns1:Stuff/text())[1]', 'nvarchar(max)') as [Else.Stuff],
    E.C.value('(ns1:StuffVal/text())[1]', 'nvarchar(max)') as [Else.StuffVal],
    E.C.value('(ns1:StuffParam/text())[1]', 'nvarchar(max)') as [Else.StuffParam],
    F.C.value('(ns1:randValue/text())[1]', 'nvarchar(max)') as [randValue]
from @data.nodes('ns0:root/ns1:FirstElement') as F(C)
    outer apply F.C.nodes('ns1:SecondElement') as S(C)
    outer apply S.C.nodes('ns1:Else') as E(C)
这一行为每个
ns0:root/ns1:FirstElement/ns1:SecondElement/ns1:Else创建一行,然后获取所需的所有值(其中一些值取自父节点)。请注意,如果您的

FirstElement
不包含任何
ns1:SecondElement/ns1:Else
节点,它将不会出现在结果集中。在这种情况下,您可能希望使用如下查询:

;with xmlnamespaces('http://herp...' as ns0, 'http://derpyderp...' as ns1)
select
    T.C.value('(../../ns1:FirstElementID/text())[1]', 'nvarchar(max)') as FirstElementID,
    T.C.value('(../../ns1:FirstEValue/text())[1]', 'nvarchar(max)') as FirstEValue,
    T.C.value('(../ns1:Something/text())[1]', 'nvarchar(max)') as Something,
    T.C.value('(ns1:Stuff/text())[1]', 'nvarchar(max)') as [Else.Stuff],
    T.C.value('(ns1:StuffVal/text())[1]', 'nvarchar(max)') as [Else.StuffVal],
    T.C.value('(ns1:StuffParam/text())[1]', 'nvarchar(max)') as [Else.StuffParam],
    T.C.value('(../../ns1:randValue/text())[1]', 'nvarchar(max)') as [randValue]
from @data.nodes('ns0:root/ns1:FirstElement/ns1:SecondElement/ns1:Else') as T(C)
;with xmlnamespaces('http://herp...' as ns0, 'http://derpyderp...' as ns1)
select
    F.C.value('(ns1:FirstElementID/text())[1]', 'nvarchar(max)') as FirstElementID,
    F.C.value('(ns1:FirstEValue/text())[1]', 'nvarchar(max)') as FirstEValue,
    S.C.value('(ns1:Something/text())[1]', 'nvarchar(max)') as Something,
    E.C.value('(ns1:Stuff/text())[1]', 'nvarchar(max)') as [Else.Stuff],
    E.C.value('(ns1:StuffVal/text())[1]', 'nvarchar(max)') as [Else.StuffVal],
    E.C.value('(ns1:StuffParam/text())[1]', 'nvarchar(max)') as [Else.StuffParam],
    F.C.value('(ns1:randValue/text())[1]', 'nvarchar(max)') as [randValue]
from @data.nodes('ns0:root/ns1:FirstElement') as F(C)
    outer apply F.C.nodes('ns1:SecondElement') as S(C)
    outer apply S.C.nodes('ns1:Else') as E(C)

谢谢,似乎正是我想要的。我会测试一下,然后再给你回复。:)一年后,我忘记了这一点,但这个回答绝对是正确答案的答案。我不得不将XML从一个文件批量插入到一个表中,然后对XML进行索引,但最终我们发现并修复了旧解决方案中的许多错误,更好地理解了整个业务需求,并以15倍的性能超越了旧解决方案。真的谢谢你!