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_preparedocument
和 sp_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 有点不稳定并且已经过时。如果您需要使用它,您需要提供到<Group>
的路径,然后按照自己的方式返回到其他元素。这应该根据您的示例 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 解析:文档解析需要太多内存