Select 某些重复 XML 节点在各个级别的名称和重复子节点作为来自所述节点内的行

Select certain repeating XML node by name at various levels & repeating sub-nodes as rows from within said node

采用以下简化的XML:

(来自第 3 方行业批发商数据提供商的非常昂贵(且大)XML 产品提要的摘录 - 即我无法控制其模式/格式/内容)

<Company>
    <Code>7786</Code>
    <Brand>
        <!-- /../ -->
        <Groups>
            <Group>
                <!-- /../ -->
                <Group>
                    <!-- /../ -->
                    <Group>
                        <!-- /../ -->
                        <Product>
                            <Pip_code>3623949</Pip_code>
                            <!-- /../ -->
                            <Other_Codes>
                                <Other_Code>
                                    <Code_Description>EAN</Code_Description>
                                    <Code_Value>5013158781351</Code_Value>
                                </Other_Code>
                                <Other_Code>
                                    <Code_Description>shipper EAN</Code_Description>
                                    <Code_Value>503158781443</Code_Value>
                                </Other_Code>
                                <Other_Code>
                                    <Code_Description>AMPP</Code_Description>
                                    <Code_Value>19192411000001107</Code_Value>
                                </Other_Code>
                                <Other_Code>
                                    <Code_Description>AMPP Manf</Code_Description>
                                    <Code_Value>2061801000001104</Code_Value>
                                </Other_Code>
                            </Other_Codes>
                        </Product>
                    </Group>
                </Group>
            </Group>
        </Groups>
    </Brand>
    <Brand>
        <!-- /../ -->
        <Groups>
            <Group>
                <!-- /../ -->
                <Product>
                    <Pip_code>3265725</Pip_code>
                    <!-- /../ -->
                    <Other_Codes>
                        <Other_Code>
                            <Code_Description>Outer EAN</Code_Description>
                            <Code_Value>5013158776531</Code_Value>
                        </Other_Code>
                        <Other_Code>
                            <Code_Description>AMPP</Code_Description>
                            <Code_Value>11521811000001106</Code_Value>
                        </Other_Code>
                        <Other_Code>
                            <Code_Description>AMPP Manf</Code_Description>
                            <Code_Value>2061801000001104</Code_Value>
                        </Other_Code>
                        <Other_Code>
                            <Code_Description>EAN</Code_Description>
                            <Code_Value>5013158776500</Code_Value>
                        </Other_Code>
                    </Other_Codes>
                </Product>
            </Group>
        </Groups>
    </Brand>
</Company>

我的任务是生成以下输出:

事实证明这是极其困难的,原因有二:

  1. 您会注意到 <product> 3623949 存在于 Groups/Group/Group/Group/(组的 3 层)中,而 <product> 3265725 存在于 Groups/Group/(1 层)中组的)-我需要 select 所有 <product> 节点,无论它们的嵌套级别如何(理想情况下,只要父节点 = <Group>

  2. 注意 <product> 中的 <Other_Codes> 节点 - 我需要 select 重复子节点 (Code_Description & Code_Value)作为两个单独的列,但还要注意 <Other_Codes> 中可能有任意数量的 <Other_Code> 节点,我需要 select 它们全部(呈现 [i] 符号无用)

我已尽力使用 TSQL OPENXML 获取此数据,但我能想到的唯一方法是为各种 Group/Group/ levels 并且我还必须使用 [0] 符号对 Other_Code 的出现次数进行硬编码 - 考虑到它们的可变性质;错了。

SELECT  *
FROM    OPENXML (@idoc, 'Company/Brand/Groups/Group/Product',2)
                        WITH (
                          PIP_code CHAR (20) 'Pip_code',
                          OtherCodeType CHAR (20) 'Other_Codes/Other_Code[1]/Code_Description',
                          OtherCodeValue CHAR (30) 'Other_Codes/Other_Code[1]/Code_Value',
                          OtherCodeType2 CHAR (20) 'Other_Codes/Other_Code[2]/Code_Description',
                          OtherCodeValue2 CHAR (30) 'Other_Codes/Other_Code[2]/Code_Value',
                          OtherCodeType3 CHAR (20) 'Other_Codes/Other_Code[3]/Code_Description',
                          OtherCodeValue3 CHAR (30) 'Other_Codes/Other_Code[3]/Code_Value'
                  )

我们更愿意在 TSQL 中执行此操作(因为此 XML 文件已在此处处理其他与此处无关的节点和路径),我们有 SQL 服务器2008、2008 R2 和 SQL Server 2014 可供我们使用,但非 SQL 解决方案也会有所帮助 - 我们在这方面确实遇到了障碍。

所以你真正想要做的是让你的选择语句成为 //Other_Codes - 双正斜杠表示你想要每个 Other_Codes 节点,无论它在层次结构中的位置如何,给你一个每个 Other_Codes 节点的行。然后,您可以指定 PipCode../../Pip_code,当然假设此层次结构对于这部分也不会一直更改(但这在语义上有何意义?)。

这个:

DECLARE @doc xml = '<Company>
    <Code>7786</Code>
    <Brand>
        <!-- /../ -->
        <Groups>
            <Group>
                <!-- /../ -->
                <Group>
                    <!-- /../ -->
                    <Group>
                        <!-- /../ -->
                        <Product>
                            <Pip_code>3623949</Pip_code>
                            <!-- /../ -->
                            <Other_Codes>
                                <Other_Code>
                                    <Code_Description>EAN</Code_Description>
                                    <Code_Value>5013158781351</Code_Value>
                                </Other_Code>
                                <Other_Code>
                                    <Code_Description>shipper EAN</Code_Description>
                                    <Code_Value>503158781443</Code_Value>
                                </Other_Code>
                                <Other_Code>
                                    <Code_Description>AMPP</Code_Description>
                                    <Code_Value>19192411000001107</Code_Value>
                                </Other_Code>
                                <Other_Code>
                                    <Code_Description>AMPP Manf</Code_Description>
                                    <Code_Value>2061801000001104</Code_Value>
                                </Other_Code>
                            </Other_Codes>
                        </Product>
                    </Group>
                </Group>
            </Group>
        </Groups>
    </Brand>
    <Brand>
        <!-- /../ -->
        <Groups>
            <Group>
                <!-- /../ -->
                <Product>
                    <Pip_code>3265725</Pip_code>
                    <!-- /../ -->
                    <Other_Codes>
                        <Other_Code>
                            <Code_Description>Outer EAN</Code_Description>
                            <Code_Value>5013158776531</Code_Value>
                        </Other_Code>
                        <Other_Code>
                            <Code_Description>AMPP</Code_Description>
                            <Code_Value>11521811000001106</Code_Value>
                        </Other_Code>
                        <Other_Code>
                            <Code_Description>AMPP Manf</Code_Description>
                            <Code_Value>2061801000001104</Code_Value>
                        </Other_Code>
                        <Other_Code>
                            <Code_Description>EAN</Code_Description>
                            <Code_Value>5013158776500</Code_Value>
                        </Other_Code>
                    </Other_Codes>
                </Product>
            </Group>
        </Groups>
    </Brand>
</Company>';

DECLARE @idoc int;

exec sp_xml_preparedocument @idoc OUTPUT, @doc;
SELECT  *
FROM    OPENXML(@idoc, '//Other_Code',1)
WITH (
    PipCode CHAR (20) '../../Pip_code',
    Code_Description CHAR(20) 'Code_Description',
    Code_Value CHAR (30) 'Code_Value'
)

产生这个:

PipCode                 Code_Description        Code_Value
-----------------------------------------------------------------
3623949                 EAN                     5013158781351                 
3623949                 shipper EAN             503158781443                  
3623949                 AMPP                    19192411000001107             
3623949                 AMPP Manf               2061801000001104              
3265725                 Outer EAN               5013158776531                 
3265725                 AMPP                    11521811000001106             
3265725                 AMPP Manf               2061801000001104              
3265725                 EAN                     5013158776500