将 XML-Blob 转换为关系 table
Convert XML-Blob to relational table
我在 SQL Server 2017 中有一个 table,包括 XML-blob,我想将数据转换为关系 table。我正在尝试在 SQL 服务器中使用 OPENXML 和 sp_xml_preparedocument 过程。 XML-blob 有点特殊(像往常一样),我找不到编写代码的正确方法。请参阅示例。
请任何人帮助我
DECLARE @XML AS XML, @hDoc AS INT
SET @XML = '<reports xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:d1p1="http://www.uc.se/schemas/ucOrderReply/" d1p1:lang="swe">
<d1p1:report d1p1:id="6611231234" d1p1:name="Full name" d1p1:styp="F31" d1p1:index="0">
<d1p1:group d1p1:id="W080" d1p1:index="0" d1p1:key="" d1p1:name="ID-uppgifter, fysiker">
<d1p1:term d1p1:id="W08001">9761123768</d1p1:term>
<d1p1:term d1p1:id="W08002">6611231234</d1p1:term>
<d1p1:term d1p1:id="W08003">First name</d1p1:term>
<d1p1:term d1p1:id="W08004">Old road 174</d1p1:term>
<d1p1:term d1p1:id="W08005">17464</d1p1:term>
<d1p1:term d1p1:id="W08006">city</d1p1:term>
</d1p1:group>
</d1p1:report>
</reports>'
EXEC sp_xml_preparedocument @hDoc OUTPUT, @XML, '<reports xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:d1p1="http://www.uc.se/schemas/ucOrderReply/" d1p1:lang="swe"/>'
SELECT id--, name, W08001, W08002, W08003, W08004, W08005, W08006 -- This is what I want
FROM OPENXML(@hDoc, 'd1p1:reports/d1p1:report/d1p1:group/d1p1:term') -- I'm not sure about this path
WITH
(
id [varchar](50) '@id' -- This is not work
--, name
--, W08001
--, W08002
--, W08003
--, W08004
--, W08005
--, W08006
)
EXEC sp_xml_removedocument @hDoc
GO
考虑到您的 XML,您 必须遵守 XML 文档中定义的 XML 命名空间!此外,我强烈建议使用内置的 XQuery 函数并避免旧的OPENXML
东西。
所以试试这个:
;WITH XMLNAMESPACES('http://www.uc.se/schemas/ucOrderReply/' AS ns)
SELECT
Id = xc.value('@ns:id', 'bigint'),
Name = xc.value('@ns:name', 'varchar(25)'),
NodeValue = xc2.value('(.)', 'varchar(50)')
FROM
@XML.nodes('/reports/ns:report') AS XT(XC)
CROSS APPLY
xc.nodes('ns:group/ns:term') AS XT2(XC2)
这应该 return 像这样:
我知道已经有了答案,但我现在正在使用的唯一目的是帮助他人。我创建了一个 table 值函数,如下所示(见下文)。好处是,无论您将哪个 XML 传递给函数,它都会将其转换为您可以查询的 table,插入另一个 table,等等。它有对我很有用。
注意:有些 xml 在顶部元素有一些带有名称空间等的特殊字符。其中一些在使用该函数之前需要稍微清理一下,但我在不到 1 分钟的时间内发生了这种情况我使用它的案例百分比。
用法:Select * 来自 [Utility].FlattenXml
CREATE FUNCTION [Utility].[FlattenXml](@xmlDoc XML)
RETURNS TABLE
AS RETURN
WITH CTE AS (
SELECT
1 AS lvl,
x.value('local-name(.)','NVARCHAR(MAX)') AS Name,
CAST(NULL AS NVARCHAR(MAX)) AS ParentName,
CAST(1 AS INT) AS ParentPosition,
CAST(N'Element' AS NVARCHAR(20)) AS NodeType,
x.value('local-name(.)','NVARCHAR(MAX)') AS FullPath,
x.value('local-name(.)','NVARCHAR(MAX)')
+ N'['
+ CAST(ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS NVARCHAR)
+ N']' AS XPath,
ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS Position,
x.value('local-name(.)','NVARCHAR(MAX)') AS Tree,
x.value('text()[1]','NVARCHAR(MAX)') AS Value,
x.query('.') AS this,
x.query('*') AS t,
CAST(CAST(1 AS VARBINARY(4)) AS VARBINARY(MAX)) AS Sort,
CAST(1 AS INT) AS ID
FROM @xmlDoc.nodes('/*') a(x)
UNION ALL
SELECT
p.lvl + 1 AS lvl,
c.value('local-name(.)','NVARCHAR(MAX)') AS Name,
CAST(p.Name AS NVARCHAR(MAX)) AS ParentName,
CAST(p.Position AS INT) AS ParentPosition,
CAST(N'Element' AS NVARCHAR(20)) AS NodeType,
CAST(p.FullPath + N'/' + c.value('local-name(.)','NVARCHAR(MAX)') AS NVARCHAR(MAX)) AS FullPath,
CAST(p.XPath + N'/'+ c.value('local-name(.)','NVARCHAR(MAX)')+ N'['+ CAST(ROW_NUMBER() OVER(PARTITION BY c.value('local-name(.)','NVARCHAR(MAX)')
ORDER BY (SELECT 1)) AS NVARCHAR)+ N']' AS NVARCHAR(MAX)) AS XPath,
ROW_NUMBER() OVER(PARTITION BY c.value('local-name(.)','NVARCHAR(MAX)')
ORDER BY (SELECT 1)) AS Position,
CAST( SPACE(2 * p.lvl - 1) + N'|' + REPLICATE(N'-', 1) + c.value('local-name(.)','NVARCHAR(MAX)') AS NVARCHAR(MAX)) AS Tree,
CAST( c.value('text()[1]','NVARCHAR(MAX)') AS NVARCHAR(MAX) ) AS Value, c.query('.') AS this,
c.query('*') AS t,
CAST(p.Sort + CAST( (lvl + 1) * 1024 + (ROW_NUMBER() OVER(ORDER BY (SELECT 1)) * 2) AS VARBINARY(4)) AS VARBINARY(MAX) ) AS Sort,
CAST((lvl + 1) * 1024 + (ROW_NUMBER() OVER(ORDER BY (SELECT 1)) * 2) AS INT)
FROM CTE p
CROSS APPLY p.t.nodes('*') b(c)), cte2 AS (
SELECT
lvl AS Depth,
Name AS NodeName,
ParentName,
ParentPosition,
NodeType,
FullPath,
XPath,
Position,
Tree AS TreeView,
Value,
this AS XMLData,
Sort,
ID
FROM cte
UNION ALL
SELECT
p.lvl,
x.value('local-name(.)','NVARCHAR(MAX)'),
p.Name,
p.Position,
CAST(N'Attribute' AS NVARCHAR(20)),
p.FullPath + N'/@' + x.value('local-name(.)','NVARCHAR(MAX)'),
p.XPath + N'/@' + x.value('local-name(.)','NVARCHAR(MAX)'),
1,
SPACE(2 * p.lvl - 1) + N'|' + REPLICATE('-', 1)
+ N'@' + x.value('local-name(.)','NVARCHAR(MAX)'),
x.value('.','NVARCHAR(MAX)'),
NULL,
p.Sort,
p.ID + 1
FROM CTE p
CROSS APPLY this.nodes('/*/@*') a(x)
)
SELECT
ROW_NUMBER() OVER(ORDER BY Sort, ID) AS ID,
ParentName, ParentPosition,Depth, NodeName, Position,
NodeType, FullPath, XPath, TreeView, Value, XMLData
FROM CTE2
我在 SQL Server 2017 中有一个 table,包括 XML-blob,我想将数据转换为关系 table。我正在尝试在 SQL 服务器中使用 OPENXML 和 sp_xml_preparedocument 过程。 XML-blob 有点特殊(像往常一样),我找不到编写代码的正确方法。请参阅示例。 请任何人帮助我
DECLARE @XML AS XML, @hDoc AS INT
SET @XML = '<reports xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:d1p1="http://www.uc.se/schemas/ucOrderReply/" d1p1:lang="swe">
<d1p1:report d1p1:id="6611231234" d1p1:name="Full name" d1p1:styp="F31" d1p1:index="0">
<d1p1:group d1p1:id="W080" d1p1:index="0" d1p1:key="" d1p1:name="ID-uppgifter, fysiker">
<d1p1:term d1p1:id="W08001">9761123768</d1p1:term>
<d1p1:term d1p1:id="W08002">6611231234</d1p1:term>
<d1p1:term d1p1:id="W08003">First name</d1p1:term>
<d1p1:term d1p1:id="W08004">Old road 174</d1p1:term>
<d1p1:term d1p1:id="W08005">17464</d1p1:term>
<d1p1:term d1p1:id="W08006">city</d1p1:term>
</d1p1:group>
</d1p1:report>
</reports>'
EXEC sp_xml_preparedocument @hDoc OUTPUT, @XML, '<reports xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:d1p1="http://www.uc.se/schemas/ucOrderReply/" d1p1:lang="swe"/>'
SELECT id--, name, W08001, W08002, W08003, W08004, W08005, W08006 -- This is what I want
FROM OPENXML(@hDoc, 'd1p1:reports/d1p1:report/d1p1:group/d1p1:term') -- I'm not sure about this path
WITH
(
id [varchar](50) '@id' -- This is not work
--, name
--, W08001
--, W08002
--, W08003
--, W08004
--, W08005
--, W08006
)
EXEC sp_xml_removedocument @hDoc
GO
考虑到您的 XML,您 必须遵守 XML 文档中定义的 XML 命名空间!此外,我强烈建议使用内置的 XQuery 函数并避免旧的OPENXML
东西。
所以试试这个:
;WITH XMLNAMESPACES('http://www.uc.se/schemas/ucOrderReply/' AS ns)
SELECT
Id = xc.value('@ns:id', 'bigint'),
Name = xc.value('@ns:name', 'varchar(25)'),
NodeValue = xc2.value('(.)', 'varchar(50)')
FROM
@XML.nodes('/reports/ns:report') AS XT(XC)
CROSS APPLY
xc.nodes('ns:group/ns:term') AS XT2(XC2)
这应该 return 像这样:
我知道已经有了答案,但我现在正在使用的唯一目的是帮助他人。我创建了一个 table 值函数,如下所示(见下文)。好处是,无论您将哪个 XML 传递给函数,它都会将其转换为您可以查询的 table,插入另一个 table,等等。它有对我很有用。
注意:有些 xml 在顶部元素有一些带有名称空间等的特殊字符。其中一些在使用该函数之前需要稍微清理一下,但我在不到 1 分钟的时间内发生了这种情况我使用它的案例百分比。
用法:Select * 来自 [Utility].FlattenXml
CREATE FUNCTION [Utility].[FlattenXml](@xmlDoc XML)
RETURNS TABLE
AS RETURN
WITH CTE AS (
SELECT
1 AS lvl,
x.value('local-name(.)','NVARCHAR(MAX)') AS Name,
CAST(NULL AS NVARCHAR(MAX)) AS ParentName,
CAST(1 AS INT) AS ParentPosition,
CAST(N'Element' AS NVARCHAR(20)) AS NodeType,
x.value('local-name(.)','NVARCHAR(MAX)') AS FullPath,
x.value('local-name(.)','NVARCHAR(MAX)')
+ N'['
+ CAST(ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS NVARCHAR)
+ N']' AS XPath,
ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS Position,
x.value('local-name(.)','NVARCHAR(MAX)') AS Tree,
x.value('text()[1]','NVARCHAR(MAX)') AS Value,
x.query('.') AS this,
x.query('*') AS t,
CAST(CAST(1 AS VARBINARY(4)) AS VARBINARY(MAX)) AS Sort,
CAST(1 AS INT) AS ID
FROM @xmlDoc.nodes('/*') a(x)
UNION ALL
SELECT
p.lvl + 1 AS lvl,
c.value('local-name(.)','NVARCHAR(MAX)') AS Name,
CAST(p.Name AS NVARCHAR(MAX)) AS ParentName,
CAST(p.Position AS INT) AS ParentPosition,
CAST(N'Element' AS NVARCHAR(20)) AS NodeType,
CAST(p.FullPath + N'/' + c.value('local-name(.)','NVARCHAR(MAX)') AS NVARCHAR(MAX)) AS FullPath,
CAST(p.XPath + N'/'+ c.value('local-name(.)','NVARCHAR(MAX)')+ N'['+ CAST(ROW_NUMBER() OVER(PARTITION BY c.value('local-name(.)','NVARCHAR(MAX)')
ORDER BY (SELECT 1)) AS NVARCHAR)+ N']' AS NVARCHAR(MAX)) AS XPath,
ROW_NUMBER() OVER(PARTITION BY c.value('local-name(.)','NVARCHAR(MAX)')
ORDER BY (SELECT 1)) AS Position,
CAST( SPACE(2 * p.lvl - 1) + N'|' + REPLICATE(N'-', 1) + c.value('local-name(.)','NVARCHAR(MAX)') AS NVARCHAR(MAX)) AS Tree,
CAST( c.value('text()[1]','NVARCHAR(MAX)') AS NVARCHAR(MAX) ) AS Value, c.query('.') AS this,
c.query('*') AS t,
CAST(p.Sort + CAST( (lvl + 1) * 1024 + (ROW_NUMBER() OVER(ORDER BY (SELECT 1)) * 2) AS VARBINARY(4)) AS VARBINARY(MAX) ) AS Sort,
CAST((lvl + 1) * 1024 + (ROW_NUMBER() OVER(ORDER BY (SELECT 1)) * 2) AS INT)
FROM CTE p
CROSS APPLY p.t.nodes('*') b(c)), cte2 AS (
SELECT
lvl AS Depth,
Name AS NodeName,
ParentName,
ParentPosition,
NodeType,
FullPath,
XPath,
Position,
Tree AS TreeView,
Value,
this AS XMLData,
Sort,
ID
FROM cte
UNION ALL
SELECT
p.lvl,
x.value('local-name(.)','NVARCHAR(MAX)'),
p.Name,
p.Position,
CAST(N'Attribute' AS NVARCHAR(20)),
p.FullPath + N'/@' + x.value('local-name(.)','NVARCHAR(MAX)'),
p.XPath + N'/@' + x.value('local-name(.)','NVARCHAR(MAX)'),
1,
SPACE(2 * p.lvl - 1) + N'|' + REPLICATE('-', 1)
+ N'@' + x.value('local-name(.)','NVARCHAR(MAX)'),
x.value('.','NVARCHAR(MAX)'),
NULL,
p.Sort,
p.ID + 1
FROM CTE p
CROSS APPLY this.nodes('/*/@*') a(x)
)
SELECT
ROW_NUMBER() OVER(ORDER BY Sort, ID) AS ID,
ParentName, ParentPosition,Depth, NodeName, Position,
NodeType, FullPath, XPath, TreeView, Value, XMLData
FROM CTE2