如何使用openxml将数据存储在表中,并在SQL中使用While循环处理多个XML

问题描述 投票:0回答:2

我有一个包含3个XML的临时表:

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

我正在尝试从其中提取一些数据到另一个临时表中,并且使用下面的代码成功做到了:

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或数据库中的任何表中。我知道这是通过While循环完成的,但是我真的不知道如何实现它。有人可以帮我解决这个问题,甚至可以使它成为存储过程吗?

sql sql-server xml openxml sql-server-openxml
2个回答
0
投票

[您应该能够在没有WHILE循环的情况下进行操作-改为将CROSS APPLYnodes()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

0
投票

这不是真正的答案,更多的是@AlwaysLearning的答案。

<< [向后导航(父轴,在您的示例中与多个../一起使用)的效果非常差。最好将APPLY的级联与.nodes()结合使用:

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

© www.soinside.com 2019 - 2024. All rights reserved.