Technical Article

Translate function for SQL Server

,

Translate8K accepts an input string (@string) and returns a new string with all occurrences of each character in @FromChar replaced by its corresponding character in @ToChar. Take the input string "1122", a @FromChar value of "12" and a @ToChar value of "AB"; the result of dbo.Translate8K('1122', '12', 'AB') would return "AABB". Each "1" is replaced by "A", each "2" is replaced by "B".

Characters in @string that don't exist in @FromChar remain unchanged. Changing the above example where @string is "112233", @FromChar is "AB" and @ToChar is "12"; the result of dbo.Translate8K('112233', '12', 'AB') returns "AABB33". When @FromChar contains more characters than @ToChar, the extra characters at the end of @FromChar that have no corresponding characters in @ToChar are simply removed from @String and don't appear in the return value.

Happy string manipulating!

CREATE FUNCTION dbo.Translate8K
(
  @String   varchar(8000), 
  @FromChar varchar(100), 
  @ToChar   varchar(100)
)
/****************************************************************************************
Purpose:
 Takes an input string (@string) and returns a new string with all occurrences of each 
 character in @FromChar replaced by its corresponding character in @ToChar. Take the
 input string "1122", a @FromChar value of "12" and a @ToChar value of "AB"; the result
 of dbo.Translate8K('1122', '12', 'AB') would return "AABB". Each "1" is replaced by "A",
 each "2" is replaced by "B". 
 
 Characters in @string that don't exist in @FromChar remain unchanged. Changing the above
 example where @string is "112233", @FromChar is "AB" and @ToChar is "12"; the result of
 dbo.Translate8K('112233', '12', 'AB') returns "AABB33". When @FromChar contains more 
 characters than @ToChar, the extra characters at the end of @FromChar that have no 
 corresponding characters in @ToChar are simply removed from @String and don't appear in
 the return value.

Compatibility: 
 SQL Server 2008+, Azure SQL Database, Azure SQL Data Warehouse & Parallel Data Warehouse
 
Parameters:
 @String   = varchar(8000); The input string to "translate"
 @FromChar = varchar(100);  Containing a series of characters to search for in @String
 @ToChar   = varchar(100);  All characters in the @FromChar will be replaced with the 
             corresponding character in the @ToChar.

Returns: varchar(8000); the "tranlated string"

Developer notes:
 1. Scalar user defined functions (udf) generally perform badly and "Inline" scalar UDFs
    generally perform much better. The only way to get this logic into an "Inline scalar 
    udf" would be to use a recursive CTE which, for this task, performs very badly. For
    more about "in scalar UDFs" see:
    http://www.sqlservercentral.com/Forums/Topic1338291-203-1.aspx

 2. When @ToChar is longer than @FromChar the replacement characters that
    the characters in @ToChar past without a corresponding character in 
    @FromChar are ignored. 

 3. Note that, becauase Translate8K is a scalar udf it will force the optimizer to choose 
    a serial plan even when a parallel plan would perform better. If you can get away
    with using the built-in T-SQL REPLACE function then use that instead. 

 4. Translate8K is case sensitive; to change this remove: "COLLATE Latin1_General_BIN"

 5. Translate8K is deterministic. For more about deterministic functions see:
    https://msdn.microsoft.com/en-us/library/ms178091.aspx

Usage Examples:
--===== (1) basic replace characters/remove characters; 
 -- replace a with A, c with C, b with x and remove $ and #
 DECLARE @string varchar(20)='###$$$aaabbbccc$$$###';
 SELECToriginal = @string, translated = dbo.Translate8K(@string,'acb#$','ACx');

--===== (2) Apply a specific format to a phone number
 DECLARE @string varchar(8000) = '(425) 555-1212';
 SELECT original = @string, Translated = dbo.Translate8K(@string,')(','-');

--===== (3) hide phone numbers, retain existing format
 WITH phoneNbrs(n,pn) AS 
 (
    SELECT 1, '(425) 555-1212' UNION ALL SELECT 2, '425.555.1212' UNION ALL
    SELECT 3, '425-555-1212'   UNION ALL SELECT 4, '4255551212' 
 )
 SELECT n, pn AS before, [after] = dbo.Translate8K(pn,x,y)
 FROM phoneNbrs
 CROSS APPLY (VALUES('()-.0123456789','()-.**********')) t(x,y);

--===== (4) Replace accent characters with normal characters (note the "double translate")
 DECLARE 
   @string   varchar(100) = 'Thë Quìck Greeñ Fox jumpëd over thë lázy dogs back!',
   @special1 varchar(32)  = 'áâãäæèïéìëíîçåñòóôöõàøúüûùýÁÃÄ',
   @normal1  varchar(32)  = 'aaaaaeieieiicanoooooaouuuuyAAAAA',
   @special2 varchar(32)  = 'ÆÈÏÉÌËÍÎÅÑÒÓÔÖÕÀØÚÜÛÙÝ!',
   @normal2  varchar(32)  = 'EIEIEIIANOOOOOAOUUUUY.';

 SELECT
   original  = @string, 
   newstring = 
     dbo.Translate8K(dbo.Translate8K(@string,@special1,@normal1),@special2,@normal2);

------------------------------------------------------------------------------
Revision History:
 Rev 00 - 20150518 - Initial Development - Alan Burstein
 Rev 01 - 20160401 - Reduced the number of rows in the tally table to only 100 numbers 
                     (the length of @ToChar). - Alan Burstein 
****************************************************************************************/RETURNS varchar(8000) WITH SCHEMABINDING AS 
BEGIN
 SELECT @string = REPLACE
  (
    @string COLLATE Latin1_General_BIN,
    SUBSTRING(@FromChar,N,1),
    SUBSTRING(@ToChar,N,1)
  )
 FROM
 (
  SELECT TOP(DATALENGTH(@FromChar)) CHECKSUM(ROW_NUMBER() OVER (ORDER BY (SELECT 1)))
  FROM (VALUES
        (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),
        (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),
        (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),
        (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),
        (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),
        (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),
        (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),
        (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),
        (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),
        (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) t(N)
 ) iTally(N) -- 100 row tally table
 RETURN @string;
END;
GO

Rate

4.2 (5)

You rated this post out of 5. Change rating

Share

Share

Rate

4.2 (5)

You rated this post out of 5. Change rating