Jeff Moden (11/15/2016)
Eirikur Eiriksson (11/15/2016)
Here is a quick solution, quite efficient😎
DECLARE @pString VARCHAR(8000) = 'Chlu' + CHAR(30) + CHAR(2) + CHAR(0) + CHAR(13) + CHAR(10) + CHAR(20) + CHAR(31) + 'emcká';
;WITH T(N) AS ( SELECT N FROM (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0))X(N))
, NUMS(N) AS ( SELECT TOP (LEN(ISNULL(@pString,CHAR(32)))) (ROW_NUMBER() OVER (ORDER BY (SELECT NULL))) FROM T T1,T T2,T T3,T T4)
SELECT
(
SELECT SUBSTRING(@pString,NM.N,1)
FROM NUMS NM
WHERE ((ASCII(SUBSTRING(@pString,NM.N,1)) - 32) & 0x7FFF) < 256
FOR XML PATH('')
) AS OUT_STR
;
Try this and see what you get...
DECLARE @pString VARCHAR(8000) = 'Chlu' + CHAR(30) + CHAR(2) + CHAR(0) + CHAR(13) + '&' + CHAR(10) + CHAR(20) + CHAR(31) + 'emcká';
;WITH T(N) AS ( SELECT N FROM (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0))X(N))
, NUMS(N) AS ( SELECT TOP (LEN(ISNULL(@pString,CHAR(32)))) (ROW_NUMBER() OVER (ORDER BY (SELECT NULL))) FROM T T1,T T2,T T3,T T4)
SELECT
(
SELECT SUBSTRING(@pString,NM.N,1)
FROM NUMS NM
WHERE ((ASCII(SUBSTRING(@pString,NM.N,1)) - 32) & 0x7FFF) < 256
FOR XML PATH('')
) AS OUT_STR
;
You need to use "TYPE" and that will make it about twice as slow.
One would use the text() function to mitigate the cost, makes a big difference by avoiding the XML reconstruction phase of the output.
😎
The cost ratio between the first and the second query is close to 1:99
DECLARE @pString VARCHAR(8000) = 'Chlu' + CHAR(30) + CHAR(2) + CHAR(0) + CHAR(13) + '&' + CHAR(10) + CHAR(20) + CHAR(31) + 'emcká';
--Better
;WITH T(N) AS ( SELECT N FROM (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0))X(N))
, NUMS(N) AS ( SELECT TOP (LEN(ISNULL(@pString,CHAR(32)))) (ROW_NUMBER() OVER (ORDER BY (SELECT NULL))) FROM T T1,T T2,T T3,T T4)
SELECT
(
SELECT SUBSTRING(@pString,NM.N,1)
FROM NUMS NM
WHERE ((ASCII(SUBSTRING(@pString,NM.N,1)) - 32) & 0x7FFF) < 256
FOR XML PATH(''), TYPE
).value('(./text())[1]','VARCHAR(8000)') AS OUT_STR
;
-- Bad
;WITH T(N) AS ( SELECT N FROM (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0))X(N))
, NUMS(N) AS ( SELECT TOP (LEN(ISNULL(@pString,CHAR(32)))) (ROW_NUMBER() OVER (ORDER BY (SELECT NULL))) FROM T T1,T T2,T T3,T T4)
SELECT
(
SELECT SUBSTRING(@pString,NM.N,1)
FROM NUMS NM
WHERE ((ASCII(SUBSTRING(@pString,NM.N,1)) - 32) & 0x7FFF) < 256
FOR XML PATH(''), TYPE
).value('(.)[1]','VARCHAR(8000)') AS OUT_STR
;