在我的应用程序中,我使用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?
答案 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进行字符串操作(由于可能的副作用和性能影响)。但我认为这是一个合法的解决方法......