如何在 table 中使用 openxml 将数据存储在 SQL 中的 While 循环中用于多个 XML
How to store data in a table using openxml with While loop in SQL for multiple XMLs
我有一个温度 table,里面有 3 XMLs:
CREATE TABLE #XMLwithOpenXML
(
Id INT IDENTITY PRIMARY KEY,
XMLData XML,
LoadedDateTime DATETIME
);
go
INSERT INTO #XMLwithOpenXML(XMLData, LoadedDateTime)
SELECT
CONVERT(XML, BulkColumn) AS BulkColumn, GETDATE()
FROM
OPENROWSET(BULK 'D:\Test\Test1.xml', SINGLE_BLOB) AS x;
INSERT INTO #XMLwithOpenXML(XMLData, LoadedDateTime)
SELECT
CONVERT(XML, BulkColumn) AS BulkColumn, GETDATE()
FROM
OPENROWSET(BULK 'D:\Test\Test2.xml', SINGLE_BLOB) AS x;
INSERT INTO #XMLwithOpenXML(XMLData, LoadedDateTime)
SELECT
CONVERT(XML, BulkColumn) AS BulkColumn, GETDATE()
FROM
OPENROWSET(BULK 'D:\Test\Test2.xml', SINGLE_BLOB) AS x;
go
我正在尝试将其中的一些数据提取到另一个临时文件中 table,并且我使用以下代码成功地做到了这一点:
DECLARE @XML AS XML, @hDoc as int, @SQL nvarchar(max)
SELECT @XML = XMLData
FROM #XMLwithOpenXML
SELECT @XML
EXEC sp_xml_preparedocument @hDoc OUTPUT, @XML
EXEC Rm #DocNameForCapsilonFieldId
SELECT
DocTypeName = typeName, DataPointName, FieldId = FieldName, ValueData
INTO
#DocNameForCapsilonFieldId
FROM
OPENXML(@hDoc, 'documents/document/dataPoints/dataPoint/field/value')
WITH
(
typeName [varchar](256) '../../../../typeName',
DataPointName [varchar](256) '../../@name',
FieldName [varchar](256) '../@name',
ValueData [varchar](256) '../value'
) AS DocTypeName
EXEC sp_xml_removedocument @hDoc
go
但问题是它只提取第一个 XML 并提取其数据。我想从所有 3 个 XML 中提取数据并将其存储在 #DocNameForCapsilonFieldId
或数据库中的任何 table 中。我知道这是通过 While 循环完成的,但我真的不知道如何实现它。有人可以帮我解决这个问题,甚至可以将其设为存储过程吗?
你应该能够在没有 WHILE
循环的情况下完成它 - 使用 CROSS APPLY
和 nodes()
和 value()
XML 函数来代替,例如类似于以下内容:
drop table if exists #DocNameForCapsilonFieldId;
create table #DocNameForCapsilonFieldId (
DocTypeName nvarchar(256),
DataPointName nvarchar(256),
FieldId nvarchar(256),
ValueData nvarchar(256)
);
drop table if exists #XMLwithOpenXML;
create table #XMLwithOpenXML (
XMLData xml
);
insert #XMLwithOpenXML values
(N'<documents>
<document>
<typeName>Example1</typeName>
<dataPoints>
<dataPoint name="dp11">
<field name="foo">
<value>42</value>
</field>
</dataPoint>
<dataPoint name="dp12">
<field name="bar">
<value>47</value>
</field>
</dataPoint>
</dataPoints>
</document>
</documents>'),
(N'<documents>
<document>
<typeName>Example2</typeName>
<dataPoints>
<dataPoint name="dp21">
<field name="baz">
<value>21</value>
</field>
</dataPoint>
<dataPoint name="dp22">
<field name="chaz">
<value>22</value>
</field>
</dataPoint>
</dataPoints>
</document>
</documents>');
insert #DocNameForCapsilonFieldId (DocTypeName, DataPointName, FieldId, ValueData)
select
x.n.value(N'../../../../typeName[1]', N'nvarchar(256)'),
x.n.value(N'../../@name[1]', N'nvarchar(256)'),
x.n.value(N'../@name[1]', N'nvarchar(256)'),
x.n.value(N'.', N'nvarchar(256)')
from #XMLwithOpenXML
cross apply XMLData.nodes(N'documents/document/dataPoints/dataPoint/field/value') x(n);
产生结果...
DocTypeName DataPointName FieldId ValueData
Example1 dp11 foo 42
Example1 dp12 bar 47
Example2 dp21 baz 21
Example2 dp22 chaz 22
首先:FROM OPENXML
,连同用于准备和删除文档的 SP,已经过时,不应再使用(存在极少数例外)。
始终尝试使用 native XML methods provided by the XML data type。即 .nodes()
,检索派生集中行数的重复元素,.value()
获取标量值。
这并不是一个真正的新答案,更多的是@AlwaysLearning 对答案的补充。
向后导航(父轴,在您的示例中使用多个../
)表现非常糟糕。更好地使用 APPLY
与 .nodes()
的级联,在 真实的 XPaths:
上越陷越深
(DDL 和示例的学分:@AlwaysLearning 的回答)
drop table if exists #XMLwithOpenXML;
create table #XMLwithOpenXML (
XMLData xml
);
insert #XMLwithOpenXML values
(N'<documents>
<document>
<typeName>Example1</typeName>
<dataPoints>
<dataPoint name="dp11">
<field name="foo">
<value>42</value>
</field>
</dataPoint>
<dataPoint name="dp12">
<field name="bar">
<value>47</value>
</field>
</dataPoint>
</dataPoints>
</document>
</documents>'),
(N'<documents>
<document>
<typeName>Example2</typeName>
<dataPoints>
<dataPoint name="dp21">
<field name="baz">
<value>21</value>
</field>
</dataPoint>
<dataPoint name="dp22">
<field name="chaz">
<value>22</value>
</field>
</dataPoint>
</dataPoints>
</document>
</documents>');
--查询:
SELECT A.doc.value('(typeName/text())[1]','nvarchar(max)') AS TypeName
,B.dp.value('@name','nvarchar(max)') AS DataPoint_Name
,C.fld.value('@name','nvarchar(max)') AS Field_Name
,C.fld.value('(value/text())[1]','int') AS Field_Value
FROM #XMLwithOpenXML t
CROSS APPLY XMLData.nodes('/documents/document') A(doc)
OUTER APPLY A.doc.nodes('dataPoints/dataPoint') B(dp)
OUTER APPLY B.dp.nodes('field') C(fld);
结果
TypeName DataPoint_Name Field_Name Field_Value
Example1 dp11 foo 42
Example1 dp12 bar 47
Example2 dp21 baz 21
Example2 dp22 chaz 22
我有一个温度 table,里面有 3 XMLs:
CREATE TABLE #XMLwithOpenXML
(
Id INT IDENTITY PRIMARY KEY,
XMLData XML,
LoadedDateTime DATETIME
);
go
INSERT INTO #XMLwithOpenXML(XMLData, LoadedDateTime)
SELECT
CONVERT(XML, BulkColumn) AS BulkColumn, GETDATE()
FROM
OPENROWSET(BULK 'D:\Test\Test1.xml', SINGLE_BLOB) AS x;
INSERT INTO #XMLwithOpenXML(XMLData, LoadedDateTime)
SELECT
CONVERT(XML, BulkColumn) AS BulkColumn, GETDATE()
FROM
OPENROWSET(BULK 'D:\Test\Test2.xml', SINGLE_BLOB) AS x;
INSERT INTO #XMLwithOpenXML(XMLData, LoadedDateTime)
SELECT
CONVERT(XML, BulkColumn) AS BulkColumn, GETDATE()
FROM
OPENROWSET(BULK 'D:\Test\Test2.xml', SINGLE_BLOB) AS x;
go
我正在尝试将其中的一些数据提取到另一个临时文件中 table,并且我使用以下代码成功地做到了这一点:
DECLARE @XML AS XML, @hDoc as int, @SQL nvarchar(max)
SELECT @XML = XMLData
FROM #XMLwithOpenXML
SELECT @XML
EXEC sp_xml_preparedocument @hDoc OUTPUT, @XML
EXEC Rm #DocNameForCapsilonFieldId
SELECT
DocTypeName = typeName, DataPointName, FieldId = FieldName, ValueData
INTO
#DocNameForCapsilonFieldId
FROM
OPENXML(@hDoc, 'documents/document/dataPoints/dataPoint/field/value')
WITH
(
typeName [varchar](256) '../../../../typeName',
DataPointName [varchar](256) '../../@name',
FieldName [varchar](256) '../@name',
ValueData [varchar](256) '../value'
) AS DocTypeName
EXEC sp_xml_removedocument @hDoc
go
但问题是它只提取第一个 XML 并提取其数据。我想从所有 3 个 XML 中提取数据并将其存储在 #DocNameForCapsilonFieldId
或数据库中的任何 table 中。我知道这是通过 While 循环完成的,但我真的不知道如何实现它。有人可以帮我解决这个问题,甚至可以将其设为存储过程吗?
你应该能够在没有 WHILE
循环的情况下完成它 - 使用 CROSS APPLY
和 nodes()
和 value()
XML 函数来代替,例如类似于以下内容:
drop table if exists #DocNameForCapsilonFieldId;
create table #DocNameForCapsilonFieldId (
DocTypeName nvarchar(256),
DataPointName nvarchar(256),
FieldId nvarchar(256),
ValueData nvarchar(256)
);
drop table if exists #XMLwithOpenXML;
create table #XMLwithOpenXML (
XMLData xml
);
insert #XMLwithOpenXML values
(N'<documents>
<document>
<typeName>Example1</typeName>
<dataPoints>
<dataPoint name="dp11">
<field name="foo">
<value>42</value>
</field>
</dataPoint>
<dataPoint name="dp12">
<field name="bar">
<value>47</value>
</field>
</dataPoint>
</dataPoints>
</document>
</documents>'),
(N'<documents>
<document>
<typeName>Example2</typeName>
<dataPoints>
<dataPoint name="dp21">
<field name="baz">
<value>21</value>
</field>
</dataPoint>
<dataPoint name="dp22">
<field name="chaz">
<value>22</value>
</field>
</dataPoint>
</dataPoints>
</document>
</documents>');
insert #DocNameForCapsilonFieldId (DocTypeName, DataPointName, FieldId, ValueData)
select
x.n.value(N'../../../../typeName[1]', N'nvarchar(256)'),
x.n.value(N'../../@name[1]', N'nvarchar(256)'),
x.n.value(N'../@name[1]', N'nvarchar(256)'),
x.n.value(N'.', N'nvarchar(256)')
from #XMLwithOpenXML
cross apply XMLData.nodes(N'documents/document/dataPoints/dataPoint/field/value') x(n);
产生结果...
DocTypeName DataPointName FieldId ValueData
Example1 dp11 foo 42
Example1 dp12 bar 47
Example2 dp21 baz 21
Example2 dp22 chaz 22
首先:FROM OPENXML
,连同用于准备和删除文档的 SP,已经过时,不应再使用(存在极少数例外)。
始终尝试使用 native XML methods provided by the XML data type。即 .nodes()
,检索派生集中行数的重复元素,.value()
获取标量值。
这并不是一个真正的新答案,更多的是@AlwaysLearning 对答案的补充。
向后导航(父轴,在您的示例中使用多个../
)表现非常糟糕。更好地使用 APPLY
与 .nodes()
的级联,在 真实的 XPaths:
(DDL 和示例的学分:@AlwaysLearning 的回答)
drop table if exists #XMLwithOpenXML;
create table #XMLwithOpenXML (
XMLData xml
);
insert #XMLwithOpenXML values
(N'<documents>
<document>
<typeName>Example1</typeName>
<dataPoints>
<dataPoint name="dp11">
<field name="foo">
<value>42</value>
</field>
</dataPoint>
<dataPoint name="dp12">
<field name="bar">
<value>47</value>
</field>
</dataPoint>
</dataPoints>
</document>
</documents>'),
(N'<documents>
<document>
<typeName>Example2</typeName>
<dataPoints>
<dataPoint name="dp21">
<field name="baz">
<value>21</value>
</field>
</dataPoint>
<dataPoint name="dp22">
<field name="chaz">
<value>22</value>
</field>
</dataPoint>
</dataPoints>
</document>
</documents>');
--查询:
SELECT A.doc.value('(typeName/text())[1]','nvarchar(max)') AS TypeName
,B.dp.value('@name','nvarchar(max)') AS DataPoint_Name
,C.fld.value('@name','nvarchar(max)') AS Field_Name
,C.fld.value('(value/text())[1]','int') AS Field_Value
FROM #XMLwithOpenXML t
CROSS APPLY XMLData.nodes('/documents/document') A(doc)
OUTER APPLY A.doc.nodes('dataPoints/dataPoint') B(dp)
OUTER APPLY B.dp.nodes('field') C(fld);
结果
TypeName DataPoint_Name Field_Name Field_Value
Example1 dp11 foo 42
Example1 dp12 bar 47
Example2 dp21 baz 21
Example2 dp22 chaz 22