When I run:
SELECT name + '&'
FROM sys.databases
FOR XML PATH('');
The code returns this:
master&tempdb&model&msdb&
What I really want is:
master&tempdb&model&msdb&
I also tried:
SELECT name + CHAR(38)
FROM sys.databases
FOR XML PATH('');
This doesn't work, too. How can I get the expected result in the first place?
Without something like:
REPLACE(CAST('master&...l&msdb&' AS NVARCHAR(MAX)), '&', '&')
The FOR XML
clause returns text by default so the result string includes XML predefined entity references, such as &
for an ampersand, to represent special characters within the XML.
To avoid entity references in the result, include TYPE
in the FOR XML
clause to return the value as strongly-typed XML instead of text, which allows invocation of a value
method on the XML node to get the value as nvarchar(MAX)
without the entity references:
SELECT (
SELECT name + '&'
FROM sys.databases
FOR XML PATH(''), TYPE
).value('(./text())[1]', 'nvarchar(MAX)');
The above example includes a trailing ampersand like your original query. One way to avoid the extraneous delimiter is with STUFF
. Below is another example that prepends the delimiter to each value and removes the unneeded first one. Also, the singleton node value (./text())[1]
specification will improve performance, a consideration for larger queries.
SELECT STUFF((
SELECT '&' + name
FROM sys.databases
FOR XML PATH(''), TYPE
).value('(./text())[1]', 'nvarchar(MAX)'), 1, 1, '');
I'll add that you can avoid the XML ugliness for aggregate string concatenation in SQL Server 2017+ and Azure SQL Database using a much cleaner and less verbose STRING_AGG
technique:
SELECT STRING_AGG(name, '&')
FROM sys.databases;
See this answer for a more detailed description of string aggegation using FOR XML
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.