0

次の XML があり、そのデータを SQL テーブルに保存したいと考えています。tblDummy という名前のテーブルがあり、「JobID」「ItemID」「SubitemID」の 3 つの列があります。Jobid と Itemid の特定の組み合わせに対して、複数の subitemsid が存在する場合があります。これどうやってするの?

<jobs>
   <job>
     <jobid>4711</jobid>
     <items>
     <itemid>1</itemid>
       <subitems>
        <subitemid>1</subitemid>
        <subitemid>2</subitemid>
       </subitems>
    <itemid>2</itemid>
       <subitems>
        <subitemid>7</subitemid>
        <subitemid>10</subitemid>
       </subitems>
    <itemid>9</itemid>
       <subitems>
        <subitemid>12</subitemid>
        <subitemid>16</subitemid>
       </subitems>
    </items>
   </job>  
 </jobs>
4

2 に答える 2

1

この XML はそのままでは、正しく解析できません。それを変更する必要があります - 各項目とそのitemidサブ項目を別のノードに配置する必要があります。そうしないと、メイン ノードの下にandノード<item>の長いリストが表示されますが、どのandノードが一緒に属しているかを知る手段がありません。 ..<itemid><subitems><items><itemid><subitems>

XML を次のように変更する必要があります。

<job>
   <jobid>4711</jobid>
   <items>
      <item>
         <itemid>1</itemid>
         <subitems>
             <subitemid>1</subitemid>
             <subitemid>2</subitemid>
         </subitems>
      </item>   
      <item>
         <itemid>2</itemid>
          <subitems>
            ......
          </subitems>
      </item>   
      ... (possibly more <item> nodes) ....
   </items>
</job>

次に、基本的に前の質問で使用したのと同じコードを使用できます-3つのレベルをカバーするように拡張されました:

CREATE PROCEDURE dbo.SaveJobs (@input XML)
AS BEGIN

;WITH JobsData AS
(    
    SELECT
        JobID = JobNode.value('(jobid)[1]', 'int'),
        ItemID = ItemNode.value('(itemid)[1]', 'int'),
        SubItemID = SubItemNode.value('.', 'int')
    FROM 
        @input.nodes('/jobs/job') AS TblJobs(JobNode)
    CROSS APPLY
        JobNode.nodes('items/item') AS TblItems(ItemNode)
    CROSS APPLY
        ItemNode.nodes('subitems/subitem') AS TblSubItems(SubItemNode)
)
INSERT INTO dbo.tblDummy(JobID, ItemID, SubItemID)
   SELECT JobID, ItemID, SubItemID
   FROM JobsData
END

基本的に、XML ノードの 3 つの「リスト」が必要です。

  • まず、値<jobs>/<job>を取得するためにすべてのノードのリストが必要ですjobid
  • これらのジョブ ノードごとに、値<items>/<item>を取得するためにネストされたリストも取得する必要があります。itemid
  • 各ノードから、次のリストも取得します<subitems>/<subitem>

これでうまくいく可能性が高いですが、かなり遅くなる可能性があります (.nodes()関数への 3 つのネストされた呼び出し!)。

アップデート:

OK、最初の呼び出しは基本的に単一の列を持つ@input.nodes('/jobs/job') AS TblJobs(JobNode)「疑似」テーブルを作成し、XML の各要素はその疑似テーブルの行に格納されているため、最初の行の列には次の XML が含まれます。TblJobsJobNode<job>JobNode

<job>
   <jobid>4711</jobid>
   <items>
      <item>
         <itemid>1</itemid>
         <subitems>
             <subitemid>1</subitemid>
             <subitemid>2</subitemid>
         </subitems>
      </item>   
      <item>
         <itemid>2</itemid>
          <subitems>
            ......
          </subitems>
      </item>   
      ... (possibly more <item> nodes) ....
   </items>
</job>

さらに各行には、<job>内部の後続の各要素の追加の XML フラグメントが含まれます。<jobs>

これらの XML フラグメントのそれぞれから、2 番目の呼び出し

CROSS APPLY JobNode.nodes('items/item') AS TblItems(ItemNode)

再び XML フラグメントのリストを選択して、現在扱っているノード内の各ノードの XML フラグメントを含むTblItems単一の列を持つ疑似テーブル ( ) にします。ItemNode<item><job>

したがって、この疑似テーブルの最初の行には次のものが含まれます。

     <item>
         <itemid>1</itemid>
         <subitems>
             <subitemid>1</subitemid>
             <subitemid>2</subitemid>
         </subitems>
      </item>   

2行目には

      <item>
         <itemid>2</itemid>
          <subitems>
            ......
          </subitems>
      </item>   

等々。

そして、3 番目の呼び出し (ご想像のとおり) は、XML 要素のリストを行として抽出し、疑似テーブルに入れ<subitem>ます (XML フラグメントのノードごとに 1 つのエントリ)。

更新#2

「JobID = JobNode.value('(jobid)[1]', 'int')」コード行は初めてです

OK -<Job>あなたが持っている XML フラグメントを考えると:

<job>
   <jobid>4711</jobid>
   <items>
     ......
   </items>
</job>

この呼び出しは、その XML に対して.value()この XPath 式 ( ) を実行するだけで、基本的にスニペットを取得します。次に、そのノードの値(内部テキスト) を抽出し、呼び出しの 2 番目のパラメーターは、これを解釈する SQL データ型を定義します。つまり、基本的にノードから を取得し、それをjobid<jobid>4711</jobid>.value()4711<jobid>int

于 2012-06-17T08:04:08.760 に答える
0

Jobid と Itemid の複合キーを主キーとして使用できます。

于 2012-06-17T08:05:05.630 に答える