Обновление столбца типа XML с условием

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

INSERT INTO XMLTEST (testXML)
values ('<R>
  <P N="Status" V="&#xD;&#xA;Draft&#xD;&#xA;" />
  <P N="Approved For Publishing" V="&#xD;&#xA;T&#xD;&#xA;" />
  <P N="Concealed From Publishing" V="&#xD;&#xA;F&#xD;&#xA;" />
  <P N="Management System" V="&#xD;&#xA;OMS&#xD;&#xA;BMS&#xD;&#xA;" />
</R>')

Мне нужно условно заменить значение "Approved For Publishing" на F, и я подумал, что лучше всего сначала проверить соответствие имени N в строке xml, прежде чем изменять значение V. Я пытался заставить работать приведенный ниже SQL, но не повезло. Может кто-нибудь помочь указать, что не так?

DECLARE @myDoc xml
SET @myDoc = (SELECT TOP 1 CAST(testXML AS VARCHAR(MAX)) FROM XMLTEST) 
Select @myDoc
SET @myDoc.modify('  
  replace value of (/R/P/@V)[1]  
  with (  
       if (/R/P/N = ''Approved For Publishing'') then  
         "F"  
       else  
          "T"  
      )  
')  
SELECT @myDoc 

2 ответа

В конце концов, нижеследующее закончилось работой, основываясь на отзывах Шнуго, Спасибо! Это было огромной помощью для меня, чтобы понять XQUERY немного лучше!!

Мне нужно было обновить содержимое столбца типа XML в SQL, и ниже приведена основная рабочая часть, необходимая как часть общего решения для массового изменения значений в старой унаследованной системе, с которой я работаю. Я уверен, что есть более элегантное решение, но мне пришлось установить переменную со специальными символами xml, чтобы сохранить строковый литерал в самом столбце - по какой-то причине я не смог заставить его работать в строке после 'then' часть блока if.

Я также изменяю его так, чтобы он только изменял значение, попадающее в условную проверку, и сохранял те же данные для остальных.

DECLARE @myDoc xml
SET @myDoc = (SELECT TOP 1 testXML FROM XMLTEST) 
UPDATE XMLTEST
SET testXML = (SELECT @myDoc.query(
N'
    <R>
    {
    let $str := "&#xD;&#xA;F&#xD;&#xA;"
    for $p in /R/P
    return
    if($p/@N="Approved For Publishing") then
     <P N="{$p/@N}" V="{$str}"/>
    else
     <P N="{$p/@N}" V="{$p/@V}"/>
    }
    </R>
'))
SELECT * FROM XMLTEST

Вывод XML после того, где значение "Approved For Publishing" установлено в "F" из "T", сохраняя специальные символы XML.

<R>
  <P N="Status" V="&#xD;&#xA;Draft&#xD;&#xA;" />
  <P N="Approved For Publishing" V="&#xD;&#xA;F&#xD;&#xA;" />
  <P N="Concealed From Publishing" V="&#xD;&#xA;F&#xD;&#xA;" />
  <P N="Management System" V="&#xD;&#xA;OMS&#xD;&#xA;BMS&#xD;&#xA;" />
</R>

Новый ответ

Специальные символы XML &#xA;а также&#xD; это не что иное, как новая строка (перевод строки (LF) и возврат каретки (CR)). Я не думаю, что это должно действительно соответствовать ценности XML. Перевод строки должен быть скорее добавлен в ваш уровень представления.

В следующем коде показано, как обновить таблицу без необходимости использования переменной или приведения.

DECLARE @tbl TABLE(ID INT IDENTITY, testXML XML);
INSERT INTO @tbl (testXML)
values ('<R>
  <P N="Status" V="&#xD;&#xA;Draft&#xD;&#xA;" />
  <P N="Approved For Publishing" V="&#xD;&#xA;T&#xD;&#xA;" />
  <P N="Concealed From Publishing" V="&#xD;&#xA;F&#xD;&#xA;" />
  <P N="Management System" V="&#xD;&#xA;OMS&#xD;&#xA;BMS&#xD;&#xA;" />
</R>')
,('<R>
  <P N="Status" V="&#xD;&#xA;Draft&#xD;&#xA;" />
  <P N="Approved For Publishing" V="&#xD;&#xA;T&#xD;&#xA;" />
  <P N="Concealed From Publishing" V="&#xD;&#xA;F&#xD;&#xA;" />
  <P N="Management System" V="&#xD;&#xA;OMS&#xD;&#xA;BMS&#xD;&#xA;" />
</R>');

UPDATE @tbl SET testXML=testXML.query(
                                    N'
                                        <R>
                                        {
                                        for $p in /R/P
                                        return
                                        if($p/@N="Approved For Publishing") then
                                         <P N="{$p/@N}" V="F"/>
                                        else
                                         <P N="{$p/@N}" V="{substring($p/@V,3,string-length($p/@V)-4)}"/>
                                        }
                                        </R>
                                    ');
SELECT * FROM @tbl;

Один из XML будет выглядеть так после действия:

<R>
  <P N="Status" V="Draft" />
  <P N="Approved For Publishing" V="F" />
  <P N="Concealed From Publishing" V="F" />
  <P N="Management System" V="OMS&#xD;&#xA;BMS" />
</R>

Новая линия между OMS а также BMS остается в этом подходе.

Предыдущий ответ

Некоторые замечания / вопросы в первую очередь?

  • Зачем вам нужно бросить это VARCHAR(MAX) а затем XML (Неявно)?
  • Вам нужно обновить значения в таблице или это временное действие?
  • Вы не можете обновить более одного значения одновременно .modify()...
  • Вы должны всегда использовать NVARCHAR если вы имеете дело с XML!
  • Есть ли необходимость в переменной @myDoc?

Вы можете попробовать это с FLWOR XQuery:

DECLARE @tbl TABLE(testXML XML);
INSERT INTO @tbl (testXML)
values ('<R>
  <P N="Status" V="&#xD;&#xA;Draft&#xD;&#xA;" />
  <P N="Approved For Publishing" V="&#xD;&#xA;T&#xD;&#xA;" />
  <P N="Concealed From Publishing" V="&#xD;&#xA;F&#xD;&#xA;" />
  <P N="Management System" V="&#xD;&#xA;OMS&#xD;&#xA;BMS&#xD;&#xA;" />
</R>');

DECLARE @myDoc xml
SET @myDoc = (SELECT TOP 1 CAST(testXML AS VARCHAR(MAX)) FROM @tbl) 

SELECT @myDoc.query(
N'
    <R>
    {
    for $p in /R/P
    return
    if($p/@N="Approved For Publishing") then
     <P N="{$p/@N}" V="F"/>
    else
     <P N="{$p/@N}" V="T"/>
    }
    </R>
')

Результат

<R>
  <P N="Status" V="T" />
  <P N="Approved For Publishing" V="F" />
  <P N="Concealed From Publishing" V="T" />
  <P N="Management System" V="T" />
</R>
Другие вопросы по тегам