我希望将xml中的记录插入到两个不同的表中。 例如
<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>
将记录插入表A中 假设身份从1开始
AID AValue
1 value
2 value
还将记录插入表B
BID AID BValue
1 1 2
2 2 3
我有这个
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
谢谢!
答案 0 :(得分: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 :(得分:1)
过程sp_xml_preparedocument
有点旧,与内存泄漏有关。如果可以,最好避免使用它。
这是一种使用较新的xml
data type抓取您寻找的数据的方法:
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
正如您所看到的,SQL Server中的XML支持相当复杂。如果可能,解析XML客户端。