Efficient way of doing “insert only if node with specific value does not exist” for an xml column

StackOverflow https://stackoverflow.com/questions/12452522

Say, I have a xml column that looks like this:

<mi>
  <m>42</m>
</mi>

Assuming table:

Word(WordId:bigint, Wordtext:nvarchar, MessageIndex:xml)

I do NOT want the following parameterized query to insert a new xml node if @MessageId already exists somewhere in the xml tree of Messageindex, but rather either fail with a deterministic error code, or silently:

begin try
    insert into Word (WordText, MessageIndex) values (@WordText, '<mi></mi>');
    update Word set MessageIndex.modify('insert (<m>{sql:variable(""@MessageId"")}</m>) into(/mi)[1]') where WordId = scope_identity();
end try
begin catch
    if error_number() = 2627
    begin
        update Word set
            MessageIndex.modify('insert (<m>{sql:variable(""@MessageId"")}</m>) into(/mi)[1]')
        where
            WordText = @WordText;
    end
    else
        throw
end catch

select WordId from Word where WordText = @WordText;

How do I make this happen efficiently?

有帮助吗?

解决方案

Something like this work for you?

DECLARE @Word TABLE (WordId bigint identity, Wordtext NVARCHAR(20), MessageIndex xml ) 

insert into @word ( messageIndex )
select '<mi> 
  <m>42</m> 
</mi>'

DECLARE @WordText NVARCHAR(20) = 'wordText'
DECLARE @messageId INT = 42

begin try 

    if exists ( select 1 from @Word where MessageIndex.exist('//mi[.=sql:variable("@MessageId")]') = 0 )
    begin
        insert into @Word (WordText, MessageIndex) values (@WordText, '<mi></mi>'); 

        update @Word set MessageIndex.modify('insert <m>{sql:variable("@MessageId")}</m> into (mi)[1]') 
        where WordId = scope_identity(); 

    end
    --else
        -- do something here?

end try 
begin catch 
    if error_number() = 2627 
    begin 
        update @Word set MessageIndex.modify('insert <m>{sql:variable("@MessageId")}</m> into (mi)[1]') 
        where WordText = @WordText; 
    end 
    else 
        throw 
end catch 

select * from @Word

其他提示

This is an older post, but I'd to share my solution, which applies when an element either exists or not:

First, we need update when element (varchar type) exists:

UPDATE PD 
SET  
[ValuesXml].modify('replace value of
(/Employee/KeyValue/text())[1] with (sql:column("x.KeyValue"))')
FROM Pdetail PD  
INNER JOIN TableXml x ON PD.PId = x.PId 
WHERE PD.[ValuesXml].exist('/Employee/KeyValue') = 1

Second, we need insert when element does not exists:

UPDATE PD
SET 
[ValuesXml].modify(
'insert <KeyValue>{sql:column("x.KeyValue")}</KeyValue> into (/Employee)[1]')
FROM RK.Pdetail PD 
INNER JOIN TableXml x ON PD.PId = x.PId 
WHERE PD.[ValuesXml].exist('/Employee/KeyValue') = 0  

If you need work with multiple instances of entities in XML you'll need use CROSS APPLY and remove the [1] singleton indicator.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top