SQL-сервер вставляет данные из таблицы в переменную XML

Как я могу вставить целую кучу строк в переменную XML без использования курсора? я знаю, что могу сделать

SET @errors.modify('insert <error>{ sql:variable("@text") }</error> as last into /errors[1]')

чтобы вставить значение переменной, но я хочу в основном сделать

SET @errors.modify(SELECT 'insert <error>{ sql:column("text") }</error>' FROM table)

что, конечно, не является юридическим синтаксисом.

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

CREATE TABLE my_table(text nvarchar(50))
INSERT INTO my_table VALUES('Message 2')
INSERT INTO my_table VALUES('Message 3')

DECLARE @errors xml
SET @errors = '<errors><error>Message 1</error></errors>'

SET @errors.modify('INSERT EVERYTHING FROM my_table MAGIC STATEMENT')

И после запуска этого кода @errors должен содержать

<errors>
  <error>Message 1</error>
  <error>Message 2</error>
  <error>Message 3</error>
</errors>

person erikkallen    schedule 20.11.2009    source источник


Ответы (3)


Разве это не проще?

set ErrorXML=(SELECT * from #MyTable FOR XML AUTO)
person Mike Knox    schedule 27.06.2010
comment
Это проще, но заменит содержимое переменной, а не добавит к ней. - person erikkallen; 27.06.2010

ПОСЛЕДНЕЕ ОБНОВЛЕНИЕ:

Хорошо, теперь, когда вопрос стал намного яснее, он нашел решение - надеюсь!!

DECLARE @errors xml
SET @errors = '<errors><error>Message 1</error></errors>'

DECLARE @newErrors XML 

SELECT @newErrors = (SELECT text AS 'error'
FROM dbo.my_table 
FOR XML PATH(''), ELEMENTS)

SELECT @errors, @newErrors

SET @errors.modify('insert sql:variable("@newErrors") as last into (/errors)[1]')

SELECT @errors

Это дает мне

@ошибки в начале

<errors><error>Message 1</error></errors>   

@newError после «волшебного» SELECT:

<error>Message 2</error><error>Message 3</error>

@ошибки после ОБНОВЛЕНИЯ:

<errors>
    <error>Message 1</error>
    <error>Message 2</error>
    <error>Message 3</error>
</errors>

ЭТО то, что вы ищете?? :-)


(старые ответы - не то, что искал ОП.....)

Вам нужно взглянуть на функцию .nodes() в SQL XQuery — она разбивает переменную XML на список узлов XML на основе выражения XPath (которое ссылается на некоторую точку в вашем XML, где у вас, вероятно, будет перечисление узлов та же структура), и это дает им «виртуальную» таблицу и имя столбца.

На основе этого элемента «Table.Column» вы можете выбрать отдельные значения из этого XML-узла — либо атрибуты, либо вложенные элементы — и вы получите их обратно как «атомарные» значения, например. как INT, VARCHAR(x), все, что вам нужно. Эти значения можно вставить в таблицу:

INSERT dbo.YourTable(col1, col2, col3, ..., colN)
  SELECT
     Error.Column.value('@attr1[1]', 'varchar(20)'),
     Error.Column.value('subitem[1]', 'int'),
     .....
     Error.Column.value('subitemN[1]', 'DateTime')
  FROM
     @xmldata.nodes('/error') AS Error(Column)

ОБНОВЛЕНИЕ: хорошо, значит, вы хотите сделать наоборот — преобразовать реляционные данные в XML — это еще проще :-)

DECLARE @NewXmlContent XML

SELECT @NewXmlContent = 
       (SELECT
          col1 as '@ID',
          col2 as 'SomeElement',
          .....
          colN as 'LastElement'
       FROM 
          dbo.YourTable
       WHERE
           ....
       FOR XML PATH('element'), ROOT('root')
       )

UPDATE YourOtherTable
SET XmlField.modify('insert sql:variable("@NewXmlContent") 
                     as last into (/XPath)[1]')
WHERE (some condition)

Это даст вам что-то вроде этого в @NewXmlContent:

<root>
   <element ID="(value of col1)">
      <SomeElement>(value of col2)</SomeElement>
      .....
      <LastElement>(value of colN)</LastElement>
   </element>
</root>

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

Новый синтаксис «FOR XML PATH» очень мощный и гибкий и позволяет делать практически все что угодно.

И, конечно же, вы можете легко сохранить это в переменную XML.

Марк

person marc_s    schedule 20.11.2009
comment
Да, но я хочу сделать наоборот: заполнить переменную xml данными из таблицы. - person erikkallen; 21.11.2009
comment
Я знаю синтаксис FOR XML, но можете ли вы сказать мне, как использовать его для добавления к существующей переменной, а не для полной замены значения. - person erikkallen; 21.11.2009
comment
Ах, хорошо - это не было ясно из вашего первоначального вопроса - ответ снова обновлен - person marc_s; 21.11.2009
comment
Этот метод также должен работать для обновления существующей переменной SQL типа XML новым содержимым, кстати. - person marc_s; 21.11.2009
comment
Ваше последнее решение выглядит многообещающе, но, к сожалению, оно не работает с сообщением об ошибке XQuery: тип SQL 'xml' не поддерживается в XQuery. При изменении типа @newErrors на nvarchar(max) происходит сбой с ошибкой «XQuery [modify()]: могут быть вставлены только узлы, не являющиеся документами. Найдена xs:string?'. - person erikkallen; 22.11.2009
comment
Кстати, я использую SQL Server 2k5. - person erikkallen; 22.11.2009
comment
Ах, я думаю, в этом проблема - я на SQL Server 2008, и возможность использовать sql:variable в операторах INSERT - одна из немногих новых функций, связанных с xml, в SQL Server 2008. Я не думаю, что вы' к сожалению, смогу сделать это в SQL Server 2005 :-( - person marc_s; 22.11.2009
comment
Разве это не говорит о том, что sql:variable подходит для sql2k5? msdn.microsoft.com/en-us/library /ms188254(v=sql.90).aspx - person Tr1stan; 12.10.2011
comment
@Tr1stan: да, для .query() звонков. Но только для тех. Ознакомьтесь с Что нового в SQL Server 2008 XML (файл DOC) и прочитайте: SQL Server 2008 поддерживает использование переменной xml в выражении вставки для вставки данных XML в существующую структуру XML.< /я> - person marc_s; 12.10.2011
comment
@marc_s жук, это просто остановило запрос, который я написал с помощью .modify, если он не будет работать с 2k5 - спасибо за разъяснение. - person Tr1stan; 12.10.2011

Основываясь на ответе Марка, вот решение, которое работает для SQL Server 2005:

CREATE TABLE #my_table(text nvarchar(50))
INSERT INTO #my_table VALUES('Message 2')
INSERT INTO #my_table VALUES('Message 3')

DECLARE @errors xml
SET @errors = '<errors><error>Message 1</error></errors>'

SELECT @errors = CAST(@errors AS nvarchar(max)) + '<new>' + (SELECT text AS 'error' FROM #my_table FOR XML PATH(''), ELEMENTS) + '</new>'

SET @errors = CAST(@errors AS nvarchar(max)) + '<new>' + @newErrors + '</new>'
SET @errors.modify('insert (/new/*) as last into (/errors)[1]')
SET @errors.modify('delete (/new)')

SELECT @errors

DROP TABLE #my_table

Вернусь

<errors>
  <error>Message 1</error>
  <error>Message 2</error>
  <error>Message 3</error>
</errors>
person erikkallen    schedule 06.01.2010