簡體   English   中英

如何在 SQL 中為多個 XML 使用帶有 While 循環的 openxml 將數據存儲在表中

[英]How to store data in a table using openxml with While loop in SQL for multiple XMLs

我有一個包含 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 循環完成的,但我真的不知道如何實現它。 有人可以幫我解決這個問題,甚至可以將其設為存儲過程嗎?

首先: FROM OPENXML以及用於准備和刪除文檔的 SP 已過時,不應再使用(存在罕見的例外情況)。

始終嘗試使用由 XML 數據類型提供的本機 XML 方法 .nodes() ,用於在派生集中檢索與多行相同的重復元素,以及.value()以獲取標量值。

這並不是一個真正的新答案,更多的是對@AlwaysLearning 答案的補充。

向后導航(父軸,在您的示例中使用多個../ )表現非常糟糕。 更好地使用.nodes()APPLY級聯,在實際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

您應該能夠在沒有WHILE循環的情況下執行此操作 - 使用帶有nodes()value() XML 函數的CROSS APPLY代替,例如如下所示:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM