XML 文档到 SQL Server 查询

Posted

技术标签:

【中文标题】XML 文档到 SQL Server 查询【英文标题】:XML Document to SQL Server Query 【发布时间】:2021-12-02 08:09:11 【问题描述】:

如何从 XML 文件获取数据到 SQL 查询,以下代码不起作用。

<FVDL>
        <EngineData>
           <RuleInfo>
             <Rule id="13EFF385-69A9-494A-9C67-951FEDAB25ED">
               <MetaInfo>
                 <Group name="package">Python Core xml</Group>
                 <Group name="inputsource">XML Document</Group>
                 <Group name="audience">broad</Group>
               </MetaInfo>
             </Rule>
            <Rule id="E9DB1C0E-025E-4EBF-A804-6C3DA413E652">
               <MetaInfo>
                 <Group name="altcategoryMIS">Python Core zipfile</Group>
                 <Group name="altcategoryGDPR">Access Violation</Group>
               </MetaInfo>
             </Rule>  
           </RuleInfo>
        </EngineData>
    </FVDL>
             
    
    USE OPENXMLTesting
    GO
    
    DECLARE @XML AS XML, @hDoc AS INT
    
    SELECT @XML = XMLData FROM XMLwithOpenXML
    
    EXEC sp_xml_preparedocument @hDoc OUTPUT, @XML
    
    Select ID, name, [Group]
    FROM OPENXML(@hDoc, 'FVDL/EngineData/RuleInfo') 
    
    WITH  
    (
    ID [varchar](100) 'Rule/@id',
    [name] [varchar](100) 'Rule/MetaInfo/Group/@name',
    [Group] [varchar](1000) 'MetaInfo/Group/.. '
    )  
    
    EXEC sp_xml_removedocument @hDoc

寻找这样的结果

ID Name Group
13EFF385-69A9-494A-9C67-951FEDAB25ED package Python Core xml
13EFF385-69A9-494A-9C67-951FEDAB25ED nputsource XML Document
13EFF385-69A9-494A-9C67-951FEDAB25ED audience broad
E9DB1C0E-025E-4EBF-A804-6C3DA413E652 altcategoryMIS Python Core zipfile
E9DB1C0E-025E-4EBF-A804-6C3DA413E652 altcategoryGDPR Access Violation

【问题讨论】:

【参考方案1】:

请尝试以下解决方案。

从 SQL Server 2005 开始,最好使用基于 w3c 标准的 XQuery 语言,同时处理 XML 数据类型。

保留 Microsoft 专有的 OPENXML 及其伙伴 sp_xml_preparedocumentsp_xml_removedocument 只是为了向后兼容过时的 SQL Server 2000。它们的使用减少到极少数的边缘情况。 强烈建议重写您的 SQL 并将其切换到 XQuery。

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, xmldata XML);
INSERT INTO @tbl (xmldata) VALUES
(N'<FVDL>
    <EngineData>
        <RuleInfo>
            <Rule id="13EFF385-69A9-494A-9C67-951FEDAB25ED">
                <MetaInfo>
                    <Group name="package">Python Core xml</Group>
                    <Group name="inputsource">XML Document</Group>
                    <Group name="audience">broad</Group>
                </MetaInfo>
            </Rule>
            <Rule id="E9DB1C0E-025E-4EBF-A804-6C3DA413E652">
                <MetaInfo>
                    <Group name="altcategoryMIS">Python Core zipfile</Group>
                    <Group name="altcategoryGDPR">Access Violation</Group>
                </MetaInfo>
            </Rule>
        </RuleInfo>
    </EngineData>
</FVDL>');
-- DDL and sample data population, end

SELECT p.value('@id', 'UNIQUEIDENTIFIER') AS ID
    , c.value('@name', 'VARCHAR(30)')AS [Name]
    , c.value('(./text())[1]', 'VARCHAR(30)')AS [Group]
FROM @tbl
    CROSS APPLY xmldata.nodes('/FVDL/EngineData/RuleInfo/Rule') AS t1(p)
    CROSS APPLY t1.p.nodes('MetaInfo/Group') AS t2(c);

输出

+--------------------------------+-----------------+---------------------+
|               ID               |      Name       |       Group         |
+--------------------------------+-----------------+---------------------+
| 13EFF385-69A9-494A-9C67-951FED | package         | Python Core xml     |
| 13EFF385-69A9-494A-9C67-951FED | inputsource     | XML Document        |
| 13EFF385-69A9-494A-9C67-951FED | audience        | broad               |
| E9DB1C0E-025E-4EBF-A804-6C3DA4 | altcategoryMIS  | Python Core zipfile |
| E9DB1C0E-025E-4EBF-A804-6C3DA4 | altcategoryGDPR | Access Violation    |
+--------------------------------+-----------------+---------------------+

【讨论】:

【参考方案2】:

OPENXML 有点不稳定并且已经过时。如果您需要使用它,您需要提供到&lt;Group&gt; 的路径,然后按照自己的方式返回到其他元素。这应该根据您的示例 XML 为您完成。

DECLARE @XML XML = N'<FVDL>
        <EngineData>
           <RuleInfo>
             <Rule id="13EFF385-69A9-494A-9C67-951FEDAB25ED">
               <MetaInfo>
                 <Group name="package">Python Core xml</Group>
                 <Group name="inputsource">XML Document</Group>
                 <Group name="audience">broad</Group>
               </MetaInfo>
             </Rule>
            <Rule id="E9DB1C0E-025E-4EBF-A804-6C3DA413E652">
               <MetaInfo>
                 <Group name="altcategoryMIS">Python Core zipfile</Group>
                 <Group name="altcategoryGDPR">Access Violation</Group>
               </MetaInfo>
             </Rule>  
           </RuleInfo>
        </EngineData>
    </FVDL>'
    
DECLARE @hDoc AS INT
    
EXEC sp_xml_preparedocument @hDoc OUTPUT, @XML
    
Select ID, name, [Group]
FROM OPENXML(@hDoc, 'FVDL/EngineData/RuleInfo/Rule/MetaInfo/Group') 
WITH  
(
    id [varchar](100) '../../@id',
    [name] [varchar](100) '@name',
    [Group] [varchar](1000) '.'
)  
    
EXEC sp_xml_removedocument @hDoc

【讨论】:

【参考方案3】:

我强烈建议你不要使用OPENXML,因为它有很多问题。

改用较新的 XQuery 函数,这些函数使用起来要简单得多

请注意.nodes 如何输入下一个。这只是必要的,因为有两个不同级别的节点需要分成不同的行。
SELECT
    ID = rl.value('@id','uniqueidentifier'),
    [name] = grp.value('@name', 'varchar(100)'),
    [Group] = grp.value('text()[1]','varchar(1000)')
FROM XMLwithOpenXML
CROSS APPLY XMLData.nodes('FVDL/EngineData/RuleInfo/Rule') x1(rl)
CROSS APPLY x1.rl.nodes('MetaInfo/Group') x2(Grp);

db<>fiddle

【讨论】:

只是想知道您的答案如何改进了 Yitzhak 的答案? 你说得对,直到我注意到他才发帖,所以我就离开了

以上是关于XML 文档到 SQL Server 查询的主要内容,如果未能解决你的问题,请参考以下文章

Sql Server XML 列替代 Document DB?

在 Sql Server 中将 xml 文档作为存储过程的参数传递是不是安全?

将 XML 转换为 SQL Server 表(cfdi 文档)

SQL Server 2008 错误 - XML 解析:文档解析需要太多内存

SQL Server Reporting Services显示XML文档错误中禁止的DTD

为啥在 MS SQL Server 中批量插入时出现“XML 解析:第 2 行,字符 0,文档语法不正确”