Обновить XML-поле без текста в T-SQL

#tsql #sql-server-2008 #xquery-sql

#tsql #sql-server-2008 #xquery-sql

Вопрос:

Я столкнулся с проблемой при обновлении поля SQL в том, что то, что я написал, отлично работает для xml-узлов с присутствующим текстом, однако оно срабатывает, когда узел пуст.

 <filemeta filetype="Video">
  <heading>TEST</heading>
  <description />
</filemeta>
  

Этот код работает нормально;

 UPDATE filemetaDB SET filemeta.modify('replace value of (/filemeta/heading/text())[1] with "TEST"');
  

Однако это нарушает;

 UPDATE filemetaDB SET filemeta.modify('replace value of (/filemeta/description/text())[1] with "notworking!"');
  

Спасибо за любую помощь.

Ответ №1:

Этот узел (/filemeta/description/text())[1] не существует в XML, поэтому заменять нечего. Вместо этого вы должны выполнить вставку. Если у вас есть сценарий, в котором у вас есть сочетание пустых узлов и узлов со значением, вы должны выполнить две инструкции update .

 declare @filemetaDB table(filemeta xml)

insert into @filemetaDB values
('<filemeta><description>Not empty</description></filemeta>'), -- Not empty node
('<filemeta><description/></filemeta>'),                       -- Empty node
('<filemeta></filemeta>')                                      -- Missing node

-- Replace value for nodes with value
update @filemetaDB
set filemeta.modify('replace value of (/filemeta/description/text())[1] with "TEST 1"')
where filemeta.exist('/filemeta/description/text()') = 1

-- Add text node for empty nodes
update @filemetaDB
set filemeta.modify('insert text{"TEST 2"} into (/filemeta/description)[1]')
where filemeta.exist('/filemeta/description/text()') = 0

select *
from @filemetaDB
  

Результат:

 filemeta
------------------------------------------------------
<filemeta><description>TEST 1</description></filemeta>
<filemeta><description>TEST 2</description></filemeta>
<filemeta />
  

Комментарии:

1. Как я могу использовать переменную в инструкции INSERT внутри метода modify?

2. @SiKni8 взгляните на использование sql: переменная(«»)

3. Попробовал это: Set @xml.modify('insert xs:string(sql:variable("@locAnchor")) into (/root/StartOne/Value6)[1]'); Я продолжаю получать ошибку: XQuery [modify()]: Only non-document nodes can be inserted. Found "xs:string ?".

4. @SiKni8 Попробуйте это set @xml.modify('insert text{sql:variable("@LocAnchor")} into (/root/StartOne/Value6)[1]');

5. Крайне неудачно. 🙂 Это все еще верно в 2018 году или были улучшения? Я не вижу в replace документах ничего, что указывало бы на то, что это было, но…

Ответ №2:

У меня был сценарий, в котором я хотел обновить ТОЛЬКО ПУСТЫЕ узлы.

 UPDATE filemetaDB SET filemeta.modify('
    insert text{"Oh, this works!!"}
    into (/filemeta/description[not(node()) and not(text())])[1]
');
  

not (node()) означает отсутствие дочерних элементов, а not (text ()) означает отсутствие текстового содержимого (однако, возможно, имеет дочерние элементы, поэтому смешивайте и сопоставляйте эти случаи по мере необходимости)

Комментарии:

1. Очень удобно, это позволяет избежать выполнения проверки exists.

Ответ №3:

вы можете проверить, есть ли у узла данные перед обновлением, такие как:

 IF EXISTS(
            SELECT  null
            FROM    filemetaDB
            WHERE   cast(filemeta.query('if (/filemeta/description[1]) then "T" else ""') as varchar) = 'T')
    BEGIN
        UPDATE filemetaDB SET filemeta.modify('replace value of (/filemeta/description/text())[1] with "notworking!"');
    END
  

Ответ №4:

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