2017-06-29 6 views
1

OpenXMLを使用してXMLの対象要素間のキャップ要素を取得するクエリを実行していますが、サポート要素の間に上限を入れたくありません。クエリは1つの値を取得するのには効果的ですが、複数の要素ノードがある場合は失敗します。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 

それはとても関与テストの私は可能であればそれはOpenXMLのように滞在したいと思いますので、より多くのようにメソッドを.nodes使用するようにクエリを変更するためにかかるかなりの時間だろう。 私は、IDと複数のキャップ要素の値を取得したいだけです。

ありがとうございます。

+0

対応するSPを用意して文書を削除するための 'FROM OPENXML'は古くなっており、これ以上は使用しないでください(まれな例外が存在します)。むしろ適切な[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は長くなり、他のキャップ要素がありますが、私は対象要素間のものだけをサポートしたいと思っています。編集された質問を参照してください。ありがとうございました! – Jt2ouan

0

あなたのXMLは二重にネストされています。 1:n<Test>の範囲にあり、<First>の範囲内にあり、1:nの範囲が<cap>の範囲にあり、<subject>の範囲内にあります。

これを照会する適切な方法は、厳密には前方 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クエリが関連<cap>の要素を取得するために、すべての<Test>要素と再び.nodes()を取得するために.nodes()を使用します。

 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; 
関連する問題