2011-01-14 11 views
0

xmlのレコードを2つの異なるテーブルに挿入しようとしています。例えばXMLからの2つのSQLテーブルへの挿入関係の維持

<Root> 
    <A> 
     <AValue>value</AValue> 
     <Children> 
      <B> 
       <BValue>2</BValue> 
      </B> 
     </Children> 
    </A> 
    <A> 
     <AValue>value</AValue> 
     <Children> 
      <B> 
       <BValue>3</BValue> 
      </B> 
     </Children> 
    </A> 
</Root> 

について は同一と仮定すると も私はこの

を有する表B

BID AID BValue 
1 1 2 
2 2 3 

にレコードを挿入1

AID AValue 
1 value 
2 value 

で開始され、テーブルにレコードを挿入します

DECLARE @idoc INT 
DECLARE @doc NVARCHAR(MAX) 

SET @doc = ' 
<Root> 
    <A> 
     <AValue>value</AValue> 
     <Children> 
      <B> 
       <BValue>2</BValue> 
      </B> 
     </Children> 
    </A> 
    <A> 
     <AValue>value</AValue> 
     <Children> 
      <B> 
       <BValue>3</BValue> 
      </B> 
     </Children> 
    </A> 
</Root> 
' 

EXEC sp_xml_preparedocument @idoc OUTPUT, @doc 

CREATE TABLE #A 
    (
     AID INT IDENTITY(1, 1) , 
     AValue varchar(100) 
    ) 

INSERT INTO #A 
     SELECT * 
     FROM OPENXML (@idoc, '/Root/A',2) 
       WITH (AValue varchar(100) 
        ) 

CREATE TABLE #B 
    (
     BID INT IDENTITY(1, 1) , 
     AID INT , 
     BValue INT 
    ) 

INSERT INTO #B 
     SELECT * 
     FROM OPENXML (@idoc, '/Root/A/Children/B',2) 
       WITH (
       AID INT, 
       BValue INT 
        ) 

SELECT * 
FROM #A 
SELECT * 
FROM #B 

DROP TABLE #A 
DROP TABLE #B 
exec sp_xml_removedocument @idoc 

ありがとう!

答えて

2

相関関係を維持する必要があります。相関関係は以下のとおりです。私はまたかなりの柔軟性を追加することでより頑強にしました。

DECLARE @A table 
    (
-- start with non-1, to show the solution is not dependent on starting at 1 
     AID INT IDENTITY(14, 1) , 
     AValue varchar(100) 
    ) 
DECLARE @B TABLE 
    (
     BID INT IDENTITY(1, 1) , 
     AID INT , 
     BValue INT 
    ) 

DECLARE @xml XML 

-- allow for duplicate values on A.AValue 
-- allow for multiple B nodes 
-- allow for A nodes without B children 
SET @xml = ' 
<Root> 
    <A> 
     <AValue>value2</AValue> 
     <Children> 
      <B> 
       <BValue>2</BValue> 
      </B> 
      <B> 
       <BValue>4</BValue> 
      </B> 
     </Children> 
    </A> 
    <A> 
     <AValue>value1</AValue> 
     <Children> 
      <B> 
       <BValue>3</BValue> 
      </B> 
     </Children> 
    </A> 
    <A> 
     <AValue>value1</AValue> 
     <Children> 
      <B> 
       <BValue>9</BValue> 
      </B> 
     </Children> 
    </A> 
    <A> 
     <AValue>valueX</AValue> 
    </A> 
</Root> 
' 

-- dump the data into a temp table for correlating A and B entries 
-- since an A can have multiple B children, ARow identifies which A it really is, 
-- multiple A records can have the same AValue 

declare @tmp table (ARow int, avalue varchar(100), bvalue int) 
INSERT @tmp (ARow, avalue, bvalue) 
SELECT X.N, X.C.value('A[1]/AValue[1]','varchar(100)'), Y.V 
FROM (
    SELECT T.C.query('.') C, row_number() over (order by C) N 
    FROM @xml.nodes('//A') T(C)) X 
OUTER APPLY (
    SELECT T2.C2.value('.','int') V 
    FROM X.C.nodes('A[1]/Children/B/BValue') T2(C2)) Y 

-- uncomment next line to see what has gone into @tmp 
-- select * from @tmp 

insert @A 
select AValue 
from (
    select distinct ARow, AValue 
    from @tmp) X 
order by ARow -- order by is important to maintain correlation 

-- get the last identity generated to correlate AID in B 
declare @lastid int 
SET @lastid = scope_identity() 

-- Max(ARow) is how many A records were entered, add back ARow to get 
-- the ID generated for the A record 

insert @B (AID, BValue) 
select @lastid-M.M+ARow, BValue 
from @tmp, (select max(ARow) M from @tmp) M 
where BValue is not null 
order by ARow 

-- check results 
select * from @A 
select * from @B 
1

手順sp_xml_preparedocumentは少し古く、メモリリークに関連しています。できるならば避ける方が良い。あなたが見ることができるように、SQL ServerでのXMLのサポートはかなり複雑である

declare @doc xml 
SET @doc = '...yourxml...' 

create table #A (AID int, AValue varchar(50)) 
create table #B (BID int identity(1,1), AID int, BValue int) 
create table #C (AID int, AValue varchar(50), BValue int) 

insert #C 
select * 
from (
     select ROW_NUMBER() over (order by 
        b.value('AValue[1]', 'varchar(50)')) as aid 
     ,  b.value('AValue[1]', 'varchar(50)') 
     ,  g.h 
     from @doc.nodes('/Root/A') a(b) 
     cross apply 
       (
       select f.value('BValue[1]', 'int') 
       from b.nodes('Children/B') e(f) 
       ) g(h) 
     ) b(aid, avalue, bvalue) 

insert #A select distinct AID, AValue from #C 
insert #B (AID, BValue) select AID, BValue from #C 

は、ここでは、xml data type以降を使用してシークデータをつかむための方法です。可能であれば、XMLクライアント側を解析します。

+0

これはAValueを使用しています。私は、Aレコードの挿入から作成される主キーを使用したいと考えています。 – TrevDev

+0

+1。 sp_xml_preparedocumentとメモリリークに関する良いアドバイス。 –

+0

AValueが一意でない場合はどうなりますか? nodetype Aの各行を何とかループする必要がありますか? – TrevDev

関連する問題