SQL Server 将表中的数据插入 XML 变量

发布于 2024-08-12 03:00:20 字数 903 浏览 1 评论 0原文

如何在不使用游标的情况下将一大堆行插入到 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>

How can I insert a whole bunch of rows into an XML variable without using a cursor?
I know I can do

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

to insert the value of a variable, but I want to basically do

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

which, of course, isn't legal syntax.

Edit: Obviously my question wasn't clear. What I want is to be able to do like this:

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')

And after running this code, @errors should contain

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

嘿嘿嘿 2024-08-19 03:00:20

这不是更简单吗?

set ErrorXML=(SELECT * from #MyTable FOR XML AUTO)

Isn't this simpler?

set ErrorXML=(SELECT * from #MyTable FOR XML AUTO)
有木有妳兜一样 2024-08-19 03:00:20

最后更新:

好的,现在问题更加清楚了,他就是解决方案 - 希望如此!

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>   

@errors在“神奇”SELECT之后的

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

@newError:更新之后的@errors:

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

你要找的吗? :-)


(旧答案 - 不是 OP 正在寻找的......)

您需要查看 SQL XQuery 中的 .nodes() 函数 - 这将分解 XML
基于 XPath 表达式(引用 XML 中可能具有相同结构的节点枚举的某个点)将变量放入 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>

并且带有 .modify() 调用的 UPDATE 语句实际上会将该内容插入到数据库中的现有 XML 字段中。这是将 XML 内容放入现有 XML 列的唯一方法 - 无法直接引用正在插入的 XML 片段中的另一个 XML 列......

新的“FOR XML PATH”语法非常强大且灵活,允许您做任何事情。

当然,您可以轻松地将其存储到 XML 变量中。

马克

LAST UPDATE:

OK, now that the question is much clearer, he's the solution - hopefully!!

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

This gives me

@errors at the beginning

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

@newError after the "magic" SELECT:

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

@errors after the UPDATE:

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

Is THAT what you're looking for?? :-)


(old answers - not what the OP was looking for.....)

You need to look at the .nodes() function in SQL XQuery - this will break up an XML
variable into a list of XML nodes, based on an XPath expression (that references some point in your XML where you are likely to have an enumeration of nodes of the same structure), and it gives them a "virtual" table and column name.

Based on that "Table.Column" element, you can select single values from that XML node - either attributes or sub-elements - and you get these back as "atomic" values, e.g. as INT, VARCHAR(x), whatever you need. These values can be inserted into the table:

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)

UPDATE: ok, so you want to do the opposite - turn relational data into XML - that's even easier :-)

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)

This will give you something like this in @NewXmlContent:

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

and the UPDATE statement with the .modify() call will actually insert that content into an existing XML field in your database. This is the only way to get XML contents into an existing XML column - there's no way of directly referencing another XML column inside a XML fragment being inserted....

The new "FOR XML PATH" syntax is very powerful and flexible and allows you to do just about anything.

And of course, you can easily store that into a XML variable.

Marc

心碎无痕… 2024-08-19 03:00:20

根据 marc 的回答,这里有一个适用于 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>

Based on marc's answer, here is a solution that works for 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

Will return

<errors>
  <error>Message 1</error>
  <error>Message 2</error>
  <error>Message 3</error>
</errors>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文