Обновление пустого тега XML в SQL Server - PullRequest
8 голосов
/ 11 мая 2010

Я пытаюсь обновить пустой тег XML в моей строке XML на сервере SQL; он говорит, что строка обновляется, когда я запускаю следующий скрипт, но когда я просматриваю XML; ничего не изменилось:

Declare @newValue varchar(100)
select @newValue = '01'

    update dbo.UploadReport
    set XmlTest.insert('replace value of (/CodeFiveReport/Owner/AgencyID/text())[1] with sql:variable("@newValue")') 
    where id = 'myId'

xml после все еще появляется как это в базе данных

<AgencyID />

Что я делаю не так?

Я пробовал @AgencyID без текста () в конце и все еще безрезультатно ...

Ответы [ 7 ]

13 голосов
/ 03 мая 2011

Использование Sql Server 2005

declare @var varchar(100)
set @var = '1234'

- вставить пробел в пустой элемент

update dbo.UploadReport 
set Form_XML.modify('insert text{" "} into (/CodeFiveReport/Owner/AgencyID/[not(text())])[1]')
WHERE id = 'myId'

- теперь, когда у нас есть узел text (), вы можете использовать замену с вашей переменной

update dbo.UploadReport 
set FORM_XML.modify('replace value of (/CodeFiveReport/Owner/AgencyID/text())[1] with sql:variable("@var")')
WHERE id = 'myId'
11 голосов
/ 11 мая 2010

Насколько я знаю по собственному опыту, вы не можете сделать это за один шаг, поскольку элемент <AgencyID/> действительно не имеет text() - поэтому вы не можете его заменить.

Возможно, вам придется использовать что-то вроде:

DECLARE @newValue VARCHAR(100)
SELECT @newValue = '01'

-- first update - add a new <AgencyID>...</AgencyID> node    
UPDATE dbo.UploadReport
SET XmlTest.modify('insert <AgencyID>{sql:variable("@newValue")}</AgencyID> as last into (/CodeFiveReport/Owner)[1]') 
WHERE id = 'myId'

-- second update - remove the empty <AgencyID /> node    
UPDATE dbo.UploadReport
SET XmlTest.modify('delete (/CodeFiveReport/Owner/AgencyID)[1]') 
WHERE id = 'myId'

Одно: вам нужно использовать операцию XmlTest.modify, а не XmlTest.insert, как в вашем посте. В столбцах XML SQL Server нет функции .insert().

4 голосов
/ 28 августа 2011

Должно быть так, чтобы работать прямо для обновления значений до пустых элементов: -

update dbo.UploadReport  
set Form_XML.modify('insert text{sql:variable("@var")} into (/CodeFiveReport/Owner/AgencyID)[1]') 
WHERE id = 'myId' 
1 голос
/ 20 декабря 2013

Лучшая практика:

  1. ТОЛЬКО обновляйте XML / записи, которые требуют обновления.
    (т.е. избегать обновления всех записей независимо от того, отличаются ли они данными).
  2. ТОЛЬКО обновляйте XML / записи один раз.
    (Например, не удаляйте каждый узел, только чтобы потом вернуться и вставить каждый узел).
  3. Повышение производительности, оказывающее минимальное влияние.
    (т. е. избегайте вставки или удаления узлов, когда подойдет простая замена или вставка текста.
  4. Не рискуйте потерять другие важные данные.
    (То есть НИКОГДА не удаляйте узел и рискуйте потерять возможные дочерние элементы, когда все, что вы делаете, это обновляет текстовое значение).
  5. Создайте что-то повторно используемое, которое будет работать для каждого сценария.
    (т. е. вопрос задает нам, как это сделать, когда вы уже знаете уникальный идентификатор.
    Однако разработайте свой ответ так, чтобы он обрабатывал несколько записей наиболее эффективным способом).

XML-столбец

Вот как я мог бы написать его для обновления поля XML в таблице:

DECLARE @newValue nVarChar(128) = '01'

--Insert a Value when the Element is Empty (i.e. <AgencyID />), so it becomes <AgencyID>01<\AgencyID>.
UPDATE dbo.UploadReport
   SET XmlTest.modify('insert text{sql:variable("@newValue")} as first into (/CodeFiveReport/Owner/AgencyID)[1]') 
 WHERE XmlTest.value('(/CodeFiveReport/Owner/AgencyID)[1]', 'nVarChar(128)') = ''--Node is: <AgencyID />
   AND id = 'myId'

--Replace the Value if Text already Exists AND is Different (e.g. <AgencyID>99<\AgencyID>).
--  Note: This will not work for Empty-Elements (i.e. <AgencyID />), which is why we perform the Update Above.
UPDATE dbo.UploadReport
   SET XmlTest.modify('replace value of (/CodeFiveReport/Owner/AgencyID)[1] with sql:variable("@newValue")') 
 WHERE XmlTest.value('(/CodeFiveReport/Owner/AgencyID)[1]', 'nVarChar(128)') != @newValue--Node is like: <AgencyID>99<\AgencyID>
   AND id = 'myId'

--Optional.  Use the Update below if it is possible for an Element to not exist at all.
UPDATE dbo.UploadReport
   SET XmlTest.modify('insert <AgencyID>{sql:variable("@newValue")}</AgencyID> as first into (/CodeFiveReport/Owner)[1]') 
 WHERE XmlTest.exist('/CodeFiveReport/Owner/AgencyID') = 0--The AgencyID Element/Node is missing entirely.
   AND id = 'myId'
   --AND XmlTest.value('(/CodeFiveReport/Owner/AgencyID)[1]', 'nVarChar(128)') IS NULL--Same thing as Exist(), only without the overhead of Casting.


Переменная XML

Если вы хотите обновить только переменную XML (а не поле XML в таблице), я бы использовал этот подход.
Я предпочитаю это, потому что вы не удаляете существующий узел или добавляете его без необходимости (который я бы представил медленнее). Вы обновляете его только тогда, когда это абсолютно необходимо.
К сведению: элемент может иметь текстовое значение и другие дочерние элементы - это разрешено спецификацией XML.

DECLARE @Xml Xml = N'<Root><Note /></Root>'--Works for: "<Root></Root>", "<Root><Note /></Root>", and "<Root><Note>Something</Note></Root>".
DECLARE @Note NVarChar(128) = 'Hello'
IF(@Xml.value('(/Root/Note)[1]', 'nVarChar(128)')  = '')    SET @Xml.modify('insert text{sql:variable("@Note")} as first into (/Root/Note)[1]')    --Node is: <Note />
IF(@Xml.value('(/Root/Note)[1]', 'nVarChar(128)') != @Note) SET @Xml.modify('replace value of (/Root/Note/text())[1] with sql:variable("@Note")')  --Node is like: <Note>Something<\Note>
IF(@Xml.exist('/Root/Note') = 0)                            SET @Xml.modify('insert <Note>{sql:variable("@Note")}</Note> as first into (/Root)[1]')--Node is missing: <Root></Root>
SELECT @Xml[@Xml]
0 голосов
/ 27 марта 2013

Если ваш столбец «XmlTest» был набран (используя XML SCHEMA COLLECTION), пустые узлы будут храниться с их тегами открытия и закрытия; такие узлы будут соответствующим образом обновлены - и ваш исходный код будет работать.

ссылка: http://msdn.microsoft.com/en-us/library/ms176009.aspx

0 голосов
/ 14 сентября 2012

Некоторые из более недавних ответов, кажется, предоставляют более простое решение этой проблемы.

Однако я искал решение, которое бы работало и в тех случаях, когда у узла / тега действительно уже есть значение. На данный момент лучший способ сделать это для обоих случаев - просто удалить узел, а затем вставить новый, например:

    set @xml.modify('
        delete (//Content/MyNode/ETA)
    ');

    set @xml.modify('
        insert <ETA>{sql:variable("@eta")}</ETA>
        into (//Content/MyNode)[1]
    ');
0 голосов
/ 21 августа 2012
SET Form_XML.modify('insert text{sql:variable("@var") into  (/CodeFiveReport/Owner/AgencyID)[1]')1]')

должно работать

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...