将节点添加到SQL Server XML是无声的失败

时间:2018-01-17 00:34:20

标签: sql-server xml

试图弄清楚为什么这个代码段不起作用。

DECLARE @changeStatus XML, @changeSet XML

SELECT @changeSet = TOP 1 ChangeSet 
FROM MyTable

SET @changeStatus = '<change id="' + CAST(NEWID() AS NVARCHAR(36)) + '" by="' + @authorizingUserName + '" byAccountId="' + CAST(@authorizingUserId AS NVARCHAR(36)) + '" when="' + CONVERT(NVARCHAR(50),GETUTCDATE(),127) + 'Z">'
                    +   '<property id="Status" name="Status" old="' + @status + '" new="Closed" />'
                    +   '<collections />'
                    + '</change>'

-- THIS DOES NOT ERROR OUT AND DOES NOT DO ANYTHING!!
SET @changeSet.modify('insert sql:variable("@changeStatus") as last into (/changes)[1]')

XML的整体结构是:

<changes>
  <change id="" by="" byAccountId="" when="">
    <property />
    <collections />
  </change>
</changes>

当我运行脚本并在处理之前和之后检查@changeSet时,它们是相同的。即:@changeStatus从未添加到@changeSet中包含的XML中。

如果原件是:

<changes>
  <change id="change01" by="" byAccountId="" when="">
    <property ... />
    <collections />
  </change>
  <change id="change02" by="" byAccountId="" when="">
    <property ... />
    <collections />
  </change>
</changes>

我希望看到:

<changes>
  <change id="change01" by="" byAccountId="" when="">
    <property ... />
    <collections />
  </change>
  <change id="change02" by="" byAccountId="" when="">
    <property ... />
    <collections />
  </change>
  <change id="82ECB3C5-D3BA-4CD2-B62C-89C083E4BAA1" by="me@mydomain.com" byAccountId="1E910737-D78C-E711-9C04-00090FFE0001" when="2018-01-17T00:12:33.700Z">
    <property id="Status" name="Status" old="In Review" new="Closed" />
    <collections />
  </change>
</changes>

有谁看到可能出错的地方?

2 个答案:

答案 0 :(得分:0)

您发布的查询一般都有效。我跑了以下测试:

http://rextester.com/RNX55555

但是,如果任何注入的参数为null,则不会插入更改,并且在您尝试插入NULL时也不会抛出任何错误。

答案 1 :(得分:0)

您永远不应该在字符串级别创建XML!

这有各种副作用。

  • 如果其中一个变量是NULL,则整个字符串将为NULL
    试试SELECT '<x>' + NULL + '</x>';
  • XML不仅仅是带有一些花哨的附加功能的文本。使用T-SQL的FOR XML肯定会! - 创建有效的XML。现在假设你的一个字符串包含禁用字符...
    试试SELECT '<x>' + 'The arrow "->" might appear in normal text' + '</x>';
    并尝试将其转换为XML
  • 许多值不以可读格式存储,而是以某种二进制格式存储。根据系统的设置,这些类型(数字,日期和时间,BLOB)的转换会有所不同。使用FOR XML将使用 - 当然! - 正确的格式输入和输出。您可以在XML中编写任何内容,但在另一个系统上可能无法读取它。

以这种方式尝试:

DECLARE @changeSet XML = N'<changes/>';
DECLARE @changeStatus XML;

SET @changeStatus=
(
    SELECT NEWID() AS [@id]
          ,'SomeAuthor' AS [@by]
          ,'SomeAuthorId' AS [@byAccountId]
          ,GETUTCDATE() AS [@when]
          ,'Status' AS [property/@id]
          ,'Status' AS [property/@name]
          ,'In Review' AS [property/@old]
          ,'Closed' AS [property/@new]
          ,'' AS [collections]
    FOR XML PATH('change')
);
--your code works fine
SET @changeSet.modify(N'insert sql:variable("@changeStatus") as last into (/changes)[1]');

--you see the first change integrated
SELECT @changeSet;

- 现在让我们再创建一个元素

SET @changeStatus=
(
    SELECT NEWID() AS [@id]
          ,'Another' AS [@by]
          ,'OneMore' AS [@byAccountId]
          ,GETUTCDATE() AS [@when]
          ,'Status' AS [property/@id]
          ,'Status' AS [property/@name]
          ,'In Review' AS [property/@old]
          ,'Closed' AS [property/@new]
          ,'' AS [collections]
    FOR XML PATH('change')
);

--and insert it
SET @changeSet.modify(N'insert sql:variable("@changeStatus") as last into (/changes)[1]');

--yeah, worked!
SELECT @changeSet;