Reputation: 20489
I have a query which converts a number into a set of ASCII characters and then attempts to concatenate them into a string:
declare @number int = 651854564
;with cte as (
select @number prev_nr
, cast(char(@number % 256) as nvarchar(100)) nextchar
union all
select prev_nr / 256 prev_nr
, cast(char((prev_nr / 256) % 256) as nvarchar(100)) nextchar
from cte
where prev_nr <> 0)
select
cast(nextchar + '' as nvarchar(100))
from cte
where prev_nr <> 0
for xml path ('');
The characters resulted from splitting the above number to individual characters is:
characters
ä
‚
Ú
&
But when attempting to concatenate them with FOR XML
they change encoding so that in the end &
is transformed and concatenated into the final result which is: ä‚Ú&
How can I fix this so I can get the correct encoding and generate the ä‚Ú&
result?
I've tried converting everything to nvarchar(100)
but I have a feeling this has no effect (and actually almost nothing to do with encoding - or at least not helpful in my scenario).
I've also tried the well known STUFF
with FOR XML
but that didn't really help.
Upvotes: 2
Views: 135
Reputation: 310
If you want to avoid XML encoding, then you could do the following:
SELECT STUFF((SELECT ','+Name AS [text()] FROM #Test FOR XML PATH(''),
TYPE).value('.', 'VARCHAR(MAX)'),1,1,'') AS 'NameList'
by adding: ,type).value('.', 'VARCHAR(MAX)'),1,1,'') you skip XML encoding.
Upvotes: 0
Reputation: 48776
I think the bigger question is: why are you using FOR XML
in the first place? XML is not well suited for this task as it has several "special" characters that need to be encoded as they have functional meaning within XML. The list is short, and even changes with context (i.e. attribute vs. element / content) as shown here:
SELECT N'& < > " ?' FOR XML PATH('');
-- & < > " ?
SELECT N'& < > " ?' AS [attr] FOR XML RAW;
-- <row attr="& < > " ?"/>
Given what you are trying to accomplish, you would be better off doing actual string concatenation as follows, and not going anywhere near XML:
DECLARE @number INT = 651854564;
DECLARE @Result NVARCHAR(MAX) = N'';
;WITH cte AS (
SELECT @number prev_nr
, CAST(CHAR(@number % 256) AS NVARCHAR(100)) nextchar
UNION ALL
SELECT prev_nr / 256 prev_nr
, CAST(CHAR((prev_nr / 256) % 256) AS NVARCHAR(100)) nextchar
FROM cte
WHERE prev_nr <> 0
)
SELECT @Result += CAST(nextchar + N'' AS NVARCHAR(100))
FROM cte
WHERE prev_nr <> 0;
SELECT @Result;
-- ä‚Ú&
I simply declared @Result NVARCHAR(MAX) = N''
, then changed the SELECT
to start with @Result +=
, and removed the FOR XML
.
Upvotes: 1
Reputation: 38023
Using the type
directive in for xml
queries
Try this:
declare @number int = 651854564
;with cte as (
select @number prev_nr
, cast(char(@number % 256) as nvarchar(100)) nextchar
union all
select prev_nr / 256 prev_nr
, cast(char((prev_nr / 256) % 256) as nvarchar(100)) nextchar
from cte
where prev_nr <> 0
)
select (select
cast(nextchar + '' as nvarchar(100))
from cte
where prev_nr <> 0
for xml path (''), type).value('.','nvarchar(max)')
rextester demo: http://rextester.com/QRUE46541
returns: ä‚Ú&
Upvotes: 5