【问题标题】:Parse XML into SQL Server table and keep order of sibling elements将 XML 解析为 SQL Server 表并保持同级元素的顺序
【发布时间】:2020-11-10 15:14:06
【问题描述】:

我需要解析下面的 XML 并在结果集中为每个 Example_Code 或 Body_text 创建一个新行 - 这些元素可以以任何顺序存在,我正在尝试创建一个如下表所示的结果集。

  declare @Xml xml = '
<Demonstrative_Examples>    
                             <Demonstrative_Example>
                                    <Intro_Text>
                                           This is the intro
                                    </Intro_Text>
                                    <Example_Code Nature="bad" >                                           
                                                  Example 1.1                                
                                    </Example_Code>
                                    <Body_Text>Body 1.1</Body_Text>
                                    <Example_Code>                            
                                                  Example 1.2          
                                    </Example_Code>
                             </Demonstrative_Example>
                             <Demonstrative_Example>
                                    <Intro_Text>
                                           This is the 2nd intro
                                    </Intro_Text>
                                    <Body_Text>Body 2.1</Body_Text>
                                    <Example_Code Nature="Good">                                           
                                                  Example 2.1                                
                                    </Example_Code>                           
                             </Demonstrative_Example>
       </Demonstrative_Examples>'


SELECT        1 as 'Demonstrative_Example_ID',
                                    1 as 'OrderID',                                                 
                                 DemonstrativeExample.x.value('(Intro_Text)[1]','nvarchar(4000)')  AS 'Intro_Text',     
                                    Body.x.value('.','nvarchar(4000)') AS 'Body_Text',                                                                             
                                    ExampleCode.x.value('.','varchar(200)') AS 'Example_Code',
                                    ExampleCode.x.value('(@Nature)[1]','nvarchar(100)') AS 'Example_CodeNature'                             
FROM   @Xml.nodes('//Demonstrative_Examples/Demonstrative_Example') AS DemonstrativeExample(x) 
                      OUTER APPLY DemonstrativeExample.x.nodes('./Body_Text') AS Body(x)
                      OUTER APPLY DemonstrativeExample.x.nodes('./Example_Code') AS ExampleCode(x)

使用上面的 T-SQL 我想返回一个结果集如下:

谁能建议如何修改 T-SQL 以获得预期的结果集?

【问题讨论】:

    标签: sql-server xml xquery


    【解决方案1】:

    这是一个基于 XQuery 和 FLWOR 表达式的解决方案。

    这是一个两步过程:

    1. 从原始 XML 组合成适当的 XML。
    2. 将第 1 步中的 XML 转换为矩形/关系格式。

    CTE 发出以下 XML(步骤 #1):

    <root>
      <r id="1" pos="1" Intro_Text="This is the intro" Body_Text="" Example_Code="Example 1.1" Nature="bad" />
      <r id="1" pos="2" Intro_Text="This is the intro" Body_Text="Body 1.1" Example_Code="" Nature="" />
      <r id="1" pos="3" Intro_Text="This is the intro" Body_Text="" Example_Code="Example 1.2" Nature="" />
      <r id="2" pos="1" Intro_Text="This is the 2nd intro" Body_Text="Body 2.1" Example_Code="" Nature="" />
      <r id="2" pos="2" Intro_Text="This is the 2nd intro" Body_Text="" Example_Code="Example 2.1" Nature="Good" />
    </root>
    

    SQL

    DECLARE @Xml XML = 
    N'<Demonstrative_Examples>
        <Demonstrative_Example>
            <Intro_Text>This is the intro</Intro_Text>
            <Example_Code Nature="bad">Example 1.1</Example_Code>
            <Body_Text>Body 1.1</Body_Text>
            <Example_Code>Example 1.2</Example_Code>
        </Demonstrative_Example>
        <Demonstrative_Example>
            <Intro_Text>This is the 2nd intro</Intro_Text>
            <Body_Text>Body 2.1</Body_Text>
            <Example_Code Nature="Good">Example 2.1</Example_Code>
        </Demonstrative_Example>
    </Demonstrative_Examples>';
    
    -- just to see
    SELECT @xml.query('<root>
    {
        for $x in /Demonstrative_Examples/Demonstrative_Example
        let $id := count(/Demonstrative_Examples/Demonstrative_Example[. << $x[1]]) + 1
            for $y in $x/*[position() gt 1]
            let $pos := count($x/*[. << $y[1]]) + 1
            let $it := $x/*[local-name()="Intro_Text"]
            return <r id="{$id}" pos="{$pos - 1}" 
                Intro_Text="{$it}" 
                Body_Text="{$y[local-name()="Body_Text"]/text()}" 
                Example_Code="{$y[local-name()="Example_Code"]/text()}"
                Nature="{$y[local-name()="Example_Code"]/@Nature}"></r>
    }
    </root>') AS xmldata;
    
    -- real deal
    ;WITH rs AS
    (
        SELECT @xml.query('<root>
        {
            for $x in /Demonstrative_Examples/Demonstrative_Example
            let $id := count(/Demonstrative_Examples/Demonstrative_Example[. << $x[1]]) + 1
                for $y in $x/*[position() gt 1]
                let $pos := count($x/*[. << $y[1]]) + 1
                let $it := $x/*[local-name()="Intro_Text"]
                return <r id="{$id}" pos="{$pos - 1}" 
                    Intro_Text="{$it}" 
                    Body_Text="{$y[local-name()="Body_Text"]/text()}" 
                    Example_Code="{$y[local-name()="Example_Code"]/text()}"
                    Nature="{$y[local-name()="Example_Code"]/@Nature}"></r>
        }
        </root>') AS xmldata
    )
    SELECT c.value('@id', 'INT') AS [ID] 
        , c.value('@pos', 'INT') AS [Order]
        , c.value('@Intro_Text', 'VARCHAR(30)') AS [Intro_Text]
        , c.value('@Body_Text', 'VARCHAR(30)') AS [Body_Text]
        , c.value('@Example_Code', 'VARCHAR(30)') AS [Example_Code]
        , c.value('@Nature', 'VARCHAR(30)') AS [Nature]
    FROM rs CROSS APPLY xmldata.nodes('/root/r') AS t(c);
    

    输出

    +----+-------+-----------------------+-----------+--------------+--------+
    | ID | Order |      Intro_Text       | Body_Text | Example_Code | Nature |
    +----+-------+-----------------------+-----------+--------------+--------+
    |  1 |     1 | This is the intro     |           | Example 1.1  | bad    |
    |  1 |     2 | This is the intro     | Body 1.1  |              |        |
    |  1 |     3 | This is the intro     |           | Example 1.2  |        |
    |  2 |     1 | This is the 2nd intro | Body 2.1  |              |        |
    |  2 |     2 | This is the 2nd intro |           | Example 2.1  | Good   |
    +----+-------+-----------------------+-----------+--------------+--------+
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-08-18
      • 1970-01-01
      • 2021-02-03
      • 2014-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多