我有XML列,内容如下
<Root>
<Element>
<ToMove/>
</Element>
<Element>
<Envelope>
<Good>SomeValue</Good>
</Envelope>
</Element>
<Element>
<ToMove/>
</Element>
<Element>
<Envelope>
<Good>SomeValue</Good>
</Envelope>
</Element>
</Root>
我想在Element和ToMove之间添加新节点Envelope。 (Element / Envelope / ToMove)使用XQuery。
我尝试将Envelope / ToMove作为兄弟添加到ToMove但插入不支持添加多个节点。单独添加Envelope然后在下一个语句中添加ToMove似乎不可能,因为已经存在不应该获取ToMove节点的Envelope节点。
有什么想法吗?
编辑:元素节点的顺序和数量是可变的。
答案 0 :(得分:1)
这可能适合你。代码中的注释描述了我的工作。
-- Setup test data two records with four elements in each
declare @Records table(ID int, Content xml)
insert into @Records values
(1, '<Root>
<Element>
<ToMove/>
</Element>
<Element>
<Envelope>
<Good>SomeValue 1</Good>
</Envelope>
</Element>
<Element>
<ToMove/>
</Element>
<Element>
<Envelope>
<Good>SomeValue 2</Good>
</Envelope>
</Element>
</Root>'),
(2, '<Root>
<Element>
<ToMove/>
</Element>
<Element>
<Envelope>
<Good>SomeValue 3</Good>
</Envelope>
</Element>
<Element>
<ToMove/>
</Element>
<Element>
<Envelope>
<Good>SomeValue 4</Good>
</Envelope>
</Element>
</Root>')
-- Split the elements, one row each to @T
declare @T table (ID int, Element xml)
insert into @T
select
ID,
r.query('.')
from @Records
cross apply Content.nodes('Root/Element') as r(r)
-- Insert Envelop/ToMove where there exist a ToMove
update @T
set Element.modify('insert <Envelope><ToMove/></Envelope> into (Element[1])')
where Element.exist('Element/ToMove') = 1
-- Remove ToMove from Element node
update @T
set Element.modify('delete Element/ToMove')
-- Save changes back to @Records, recombine elements
update @Records
set Content =
(
select (select T.Element)
from @T as T
where T.ID = R.ID
for xml path('Root')
)
from @Records as R
--Result
select *
from @Records
答案 1 :(得分:1)
我最初的问题是我正在向多个目标节点添加新节点。我设法使用两个while循环完成此任务。首先,我遍历包含Element/ToMove
节点的所有记录,然后在每个记录中,我遍历Element/ToMove
节点的所有实例并添加为兄弟节点Envelope/ToMove
。最后一步,我删除了Element/ToMove
的所有实例。
我最终得到了以下代码:
-- Create table that will temporarily hold matching records
CREATE TABLE #UpdatedRecords
(
ExistingId int,
NewContent xml,
IsProcessed bit
)
INSERT INTO #UpdatedRecords
SELECT Id,
Content,
0 -- At the beginning, records are not processed
FROM Records
WHERE Content.exist( '//Element/ToMove' ) = 1
DECLARE @HasMore bit
DECLARE @Id int
DECLARE @Content xml
DECLARE @Position int
SET @HasMore = 1
WHILE ( @HasMore = 1 )
BEGIN
-- Select next unprocessed record
SELECT @Id = ExistingId, @Content = NewContent
FROM #UpdatedRecords
WHERE IsProcessed = 0
IF @Id IS NULL
SET @HasMore = 0
ELSE
BEGIN
-- Prepare new Content
SET @Position = 1
WHILE ( @Content.exist('(//Element/ToMove)[sql:variable("@Position")]') = 1 )
BEGIN
SET @Content.modify
('
insert <Envelope><ToMove /></Envelope> after ((//Element/ToMove)[sql:variable("@Position")])[1]
')
SET @Position = @Position + 1
END
-- Update Content and mark record as processed
UPDATE #UpdatedRecords
SET NewContent = @Content,
IsProcessed = 1
WHERE ExistingId = @Id
END
-- Reset Id
SET @Id = NULL
END
Update #UpdatedRecords
SET NewContent.modify('delete //Element/ToMove')
-- Update original records
UPDATE Records
SET Contents = NewContents
FROM #UpdatedRecords
WHERE Id = ExistingId