如何在T-SQL的XML类型中使用&字符?

时间:2018-12-01 03:12:46

标签: sql sql-server xml tsql escaping

当我跑步时:

SELECT name + '&' 
FROM sys.databases 
FOR XML PATH('');

代码返回以下内容:

master&tempdb&model&msdb&

我真正想要的是:

master&tempdb&model&msdb&

我也尝试过:

SELECT name + CHAR(38) 
FROM sys.databases 
FOR XML PATH(''); 

这也不起作用。首先如何获得预期的结果?

没有类似的内容

REPLACE(CAST('master&amp...l&msdb&' AS NVARCHAR(MAX)), '&', '&')

1 个答案:

答案 0 :(得分:2)

FOR XML子句默认情况下返回文本,因此结果字符串包括XML预定义的实体引用,例如用于表示与符号的&,以表示XML中的特殊字符。

为避免在结果中引用实体,请在TYPE子句中包含FOR XML,以强类型XML而不是文本的形式返回值,从而可以在上调用value方法XML节点以获取值为nvarchar(MAX)的值,而没有实体引用:

SELECT (
    SELECT name + '&'
    FROM sys.databases
    FOR XML PATH(''), TYPE
    ).value('(./text())[1]', 'nvarchar(MAX)');

上面的示例包含跟您的原始查询类似的结尾的&符号。避免不必要的定界符的一种方法是使用STUFF。下面是另一个示例,该示例将分隔符添加到每个值之前,并删除不需要的第一个。同样,单例节点值(./text())[1]的指定将提高性能,这是一个考虑因素 用于更大的查询。

SELECT STUFF((
    SELECT '&' + name
    FROM sys.databases
    FOR XML PATH(''), TYPE
    ).value('(./text())[1]', 'nvarchar(MAX)'), 1, 1, '');

我要补充一点,您可以使用更简洁,更不复杂的STRING_AGG技术来避免SQL Server 2017+和Azure SQL数据库中聚合字符串连接的XML丑陋:

SELECT STRING_AGG(name, '&')
FROM sys.databases;

有关使用FOR XML进行字符串聚合的详细说明,请参见this answer