Обновление узлов данных xml путем передачи переменной SQL

#sql-server #xml #nodes

#sql-сервер #xml #узлы

Вопрос:

У меня есть следующий XML, и мне нужно обновить указанный на основе параметра:

 <DOPremium>
    <BasePremium>337500</BasePremium>
    <TotalPremium>337500</TotalPremium>
    <NettPremium>337500</NettPremium>
    <GrossPremium>337500</GrossPremium>
    <OptionId>0</OptionId>
</DOPremium>
<DOPremium>
     <BasePremium>337500</BasePremium>
     <TotalPremium>337500</TotalPremium>
     <NettPremium>337500</NettPremium>
     <GrossPremium>337500</GrossPremium>
     <OptionId>1</OptionId>
</DOPremium>
<DOPremium>
     <BasePremium>337500</BasePremium>
     <TotalPremium>337500</TotalPremium>
     <NettPremium>337500</NettPremium>
     <GrossPremium>337500</GrossPremium>
     <OptionId>2</OptionId>
</DOPremium>
  

Я пытаюсь обновить соответствующие узлы на основе выбора DOPremium объекта, но я не могу этого сделать. Может кто-нибудь проверить, где я ошибаюсь?

 SET @NewXmlValue = N' <BasePremium>[sql:variable("@R15_premium")]</BasePremium>'
SET @DataXml.modify('delete /*/Premiums/DOPremium/BasePremium[sql:variable("@OptionID")]')          
SET @DataXml.modify('insert sql:variable("@NewXmlValue") into (/*/Premiums/DOPremium[sql:variable("@OptionID")])[1]')           

-- Add TotalPremium
SET @NewXmlValue = N' <TotalPremium>[sql:variable("@R15_premium")]</TotalPremium>'
SET @DataXml.modify('delete /*/Premiums/DOPremium/TotalPremium[sql:variable("@OptionID")]')         
SET @DataXml.modify('insert sql:variable("@NewXmlValue") into (/*/Premiums/DOPremium[sql:variable("@OptionID")])[1]')
  

Ответ №1:

Хорошо, во-первых, это не может работать:

 SET @NewXmlValue = N'<BasePremium>[sql:variable("@R15_premium")]</BasePremium>'
  

sql:variable() интерпретируется только как функция в операции XQuery. Это не операция XQuery, поэтому она будет просто текстовой вставкой sql:variable(...) . Если вам нужен фактический узел XML с текстовым значением переменной, вам придется действовать немного более обходным путем:

 SET @NewXmlValue = '';
SET @NewXmlValue = (SELECT @NewXmlValue.query('<BasePremium>{sql:variable("@R15_premium")}</BasePremium>'));
  

Этот подход (и другие) можно найти в документах. (В этом очень простом случае объединение строк в T-SQL, конечно, также работает, но в целом это не очень хорошая идея, потому что она не заботится об экранировании XML при необходимости.)

Синтаксис для выбора нужного DOPremium узла также нуждается в доработке — /BasePremium[sql:variable("@OptionID")] является законным, но это означает « BasePremium узел, который последовательно нумеруется от 1, имеет номер @OptionID «. Если @OptionID предполагается, что она соответствует тому, что находится в OptionID , это не тот способ ее написания.

Если вы намеревались написать «измените содержимое BasePremium значения узла на OptionID текст, равный @OptionID значению @R15_premium «, вот как вы это делаете (ну, один из способов сделать это):

 SET @DataXml.modify('
    replace value of (
        /*
        /Premiums
        /DOPremium[child::OptionId/.=sql:variable("@OptionID")]
        /BasePremium
        /text()
    )[1] 
    with sql:variable("@R15_premium")')
  

И что-то подобное для TotalPremium . Вы можете, конечно, также заменить целые узлы, но здесь это кажется ненужным.