在TSQL中使用变量节点名构造xml

时间:2018-03-08 13:33:52

标签: sql-server xml tsql generics for-xml

在我的应用程序中,我使用FOR XML PATH()运行一个相当复杂的查询来构造xml结果。我在几个存储过程中使用此查询,但每个根节点和第一级节点名称是不同的。我想要做的是创建一个标量用户定义函数,它将两个节点名称作为参数并返回正确的xml。预期的输出看起来像这样:

<{root node name}>
    <{first level node name}  attr1="value1" attr2="value2">
        <detail attr1="value3">
            <error code="1" descr="some error"/>
            <error code="3" descr="some other error"/>
        </detail>
    </{first level node name}>
    <error code="4" descr="yet another error"/>
</{root node name}>

将{root node name}和{first level node name}作为参数传递

我知道我可以使用动态SQL来做到这一点,但它可能非常麻烦,我想避免它。我也可以在C#或使用XSLT轻松完成,但我需要在SQL中完全执行此操作,因为它将从SQL服务代理处理程序中调用。

不幸的是FOR XML PATH需要节点名称的文字。我还尝试使用已知的通用节点名创建xml,然后尝试使用XQuery替换它们,但这也需要文字。 XQuery都必须是文字,节点构造函数中使用的节点名称也必须是文字(不能使用sql:variable()

有没有办法用动态节点名创建XML?

1 个答案:

答案 0 :(得分:1)

由于元素名称是根据结果集的列名构建的,所以这不起作用(动态SQL或CLR除外),但有救援:

DECLARE @rowName NVARCHAR(10)=N'TheRow';
DECLARE @rootName NVARCHAR(10)=N'TheRoot';

DECLARE @OutputXml XML=
CAST(
    REPLACE(REPLACE(
    CAST((SELECT TOP 2 [name],[type] 
          FROM sys.objects 
          FOR XML PATH(N'ThisIsAStringOnlyUsedAsRowElementName')
                 ,ROOT(N'TheSameIdeaForTheRootName')
                 ,TYPE) AS NVARCHAR(MAX))
    ,N'ThisIsAStringOnlyUsedAsRowElementName',@rowName)
    ,N'TheSameIdeaForTheRootName',@rootName) AS XML);


SELECT @outputXML;

结果

<TheRoot>
  <TheRow>
    <name>spt_fallback_db</name>
    <type>U </type>
  </TheRow>
  <TheRow>
    <name>spt_fallback_dev</name>
    <type>U </type>
  </TheRow>
</TheRoot>

一般情况下,我会避免对XML进行字符串操作(由于可能的副作用和性能影响)。但我认为这是一个合法的解决方法......