2017-06-29 47 views
1

我在查詢使用OpenXML檢索XML中的主題元素之間的帽元素我不想在支持元素之間的上限。該查詢很適合檢索一個值,但在有多個元素節點時會失敗。SQL使用OpenXML檢索多個元素

 <First> 
     <Test id="83847"> 
      <subject> 
       <cap>15</cap> 
       <cap>25</cap> 
       <cap>100</cap> 
      </subject> 
      <support> 
       <cap>9</cap> 
      </support> 
      </Test> 
     <Test id="83848"> 
      <subject> 
       <cap>150</cap> 
       <cap>2</cap> 
       <cap>10</cap> 
      </subject> 
      <support> 
       <cap>9</cap> 
      </support> 
      </Test> 
     </First> 

CREATE Table #XmlTemp(XmlField Xml); 
Set Nocount On; 
Insert Into #XmlTemp(XmlField) 
Select '<First> 
     <Test id="83847"> 
      <subject> 
       <cap>15</cap> 
       <cap>25</cap> 
       <cap>100</cap> 
      </subject> 
      <support> 
       <cap>9</cap> 
      </support> 
      </Test> 
     <Test id="83848"> 
      <subject> 
       <cap>150</cap> 
       <cap>2</cap> 
       <cap>10</cap> 
      </subject> 
      <support> 
       <cap>9</cap> 
      </support> 
      </Test> 
     </First>'As XmlField; 

Declare @xmlData Xml; 
Select @xmlData = XmlField From #XmlTemp; 

Declare @document int; 
Exec sp_xml_preparedocument @document Output, @xmlData, NULL; 


SELECT ID,Cap FROM(
SELECT ID,Cap FROM OpenXml(@document,'./First/Test', 0) With (ID varchar(max)'./@id', Cap Varchar(max) './subject/cap')) alias 

drop table #xmltemp 

這將會是相當費時更改查詢使用.nodes方法,更是因爲參與這樣的測試,我想如果可能的話,留下來爲OpenXML的時間。 我只想檢索出ID,然後檢索多個cap元素值。

謝謝你的時間。

+0

'從OPENXML'與相應的SP準備和刪除文檔已過時,不應再使用(極少有例外)。而是使用適當的[XML數據類型提供的方法](https://msdn.microsoft.com/en-us/library/ms190798.aspx)。 – Shnugo

回答

1

我看不到爲什麼使用.nodes的查詢很複雜。只是

SELECT t.n.value('(/First/Test/@id)[1]', 'int') id 
    , t.n.value('(.)[1]', 'int') cap 
from @xmlData.nodes('./First/Test/subject/cap') t(n); 

而且OpenXML的版本

SELECT ID,Cap FROM(
    SELECT ID,Cap 
    FROM OpenXml(@document,'./First/Test/subject/cap', 0) 
     With (ID varchar(max) '/First/Test/@id' 
      , Cap Varchar(max) '.')) alias 

版本的編輯問題

SELECT ID,Cap FROM(
    SELECT ID,Cap 
    FROM OpenXml(@document,'/First/Test/subject/cap', 0) 
     With (ID varchar(max) '../../@id' 
      , Cap Varchar(max) '.')) alias 

它只返回subject/cap@id適當父:

ID Cap 
1 83847 15 
2 83847 25 
3 83847 100 
4 83848 150 
5 83848 2 
6 83848 10 
+0

不復雜。在測試希望避免的更改時,只需要額外的開銷。 – Jt2ouan

+0

我明白了。看編輯版本。 – Serg

+0

我想這使得它有點更具挑戰性,但是XML更長,並且還有其他cap元素,但是我只想要主題元素之間不支持的元素。您的代碼只抓取第一個id屬性,而可能有多個。看到編輯的問題。謝謝! – Jt2ouan

0

您的XML是雙重嵌套的。您在<First>之內有個<Test>個元素,並且在<subject>之間又有1:n<cap>個元素。

查詢正確的方法是潛入XML嚴格向前

CREATE Table #XmlTemp(XmlField Xml); 
Set Nocount On; 
Insert Into #XmlTemp(XmlField) 
Select '<First> 
     <Test id="83847"> 
      <subject> 
       <cap>15</cap> 
       <cap>25</cap> 
       <cap>100</cap> 
      </subject> 
      <support> 
       <cap>9</cap> 
      </support> 
      </Test> 
     <Test id="83848"> 
      <subject> 
       <cap>150</cap> 
       <cap>2</cap> 
       <cap>10</cap> 
      </subject> 
      <support> 
       <cap>9</cap> 
      </support> 
      </Test> 
     </First>'As XmlField; 

--The查詢將使用.nodes()讓所有<Test>元素,並再次.nodes()得到相關<cap>元素:

 SELECT t.value('@id', 'int') id 
      ,c.value('text()[1]', 'int') cap 
    from #XmlTemp AS tbl 
    CROSS APPLY tbl.XmlField.nodes('/First/Test') AS A(t) 
    CROSS APPLY A.t.nodes('subject/cap') AS B(c); 
GO 
DROP TABLE #XmlTemp;