String REPLACEMENT Question

  • I'm wondering how might I search every character in a string for numeric and alpha characters?

    Numeric characters I want to replace with a # sign. Alpha characters I want to replace with an A.

    I know how to use REPLACE Function. But that only search a record for each appearance of ONE set of characters. I want every number or alphabet changed.

    I could do something very long and complicated like

    SELECT REPLACE(REPLACE(REPLACE(ColumnName, 1, '#'), 2,'#'), 3,'#')

    FROM TableName

    But this doesn't work so well with Alphabets as there are 26 characters and its not very maintenance friendly.

    Thanks!

  • Embedded REPLACEs is your best option really, from a performance standpoint.

    You could generate the REPLACE statements so you didn't have to write them by hand.

    SQL DBA,SQL Server MVP(07, 08, 09) "It's a dog-eat-dog world, and I'm wearing Milk-Bone underwear." "Norm", on "Cheers". Also from "Cheers", from "Carla": "You need to know 3 things about Tortelli men: Tortelli men draw women like flies; Tortelli men treat women like flies; Tortelli men's brains are in their flies".

  • You mean something like this?

    DECLARE @TestStr VARCHAR(20) = 'Q2ERY56920TYEU';

    SELECT @TestStr;

    WITH eTally(n) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM sys.all_columns a CROSS JOIN sys.all_columns b)

    SELECT

    NewString = STUFF((SELECT '' + NewChar FROM

    (SELECT TOP (LEN(@TestStr))

    n,

    CASE WHEN SUBSTRING(@TestStr,n,1) NOT LIKE '[^0-9]' THEN '#' ELSE 'A' END NewChar

    FROM

    eTally)dt

    ORDER BY n

    FOR XML PATH(''),TYPE).value('.','varchar(max)'),1,0,'');

  • Lynn Pettis (1/3/2013)


    You mean something like this?

    DECLARE @TestStr VARCHAR(20) = 'QWERY56920TYEU';

    SELECT @TestStr;

    WITH eTally(n) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM sys.all_columns a CROSS JOIN sys.all_columns b)

    SELECT

    NewString = STUFF((SELECT '' + NewChar FROM

    (SELECT TOP (LEN(@TestStr))

    n,

    CASE WHEN SUBSTRING(@TestStr,n,1) NOT LIKE '[^0-9]' THEN '#' ELSE 'A' END NewChar

    FROM

    eTally)dt

    FOR XML PATH(''),TYPE).value('.','varchar(max)'),1,0,'');

    Couldn't the first test just be "LIKE [0-9]"?

    And I think you need a second WHEN to check for alphas, with an ELSE that uses the original character as is.

    SQL DBA,SQL Server MVP(07, 08, 09) "It's a dog-eat-dog world, and I'm wearing Milk-Bone underwear." "Norm", on "Cheers". Also from "Cheers", from "Carla": "You need to know 3 things about Tortelli men: Tortelli men draw women like flies; Tortelli men treat women like flies; Tortelli men's brains are in their flies".

  • Depends on the OPs actually requirements.

  • declare @t table(id int, string varchar(500))

    insert @t values (1,'abc0123456789'),(2,'123abcdefghijklmnopqrstuvwzyz');

    with cte as

    (

    select id,1 nbr, cast(string as varchar(500)) string

    from @t

    union all

    select id,nbr+1, cast(

    case when patindex('%[0-9]%',string) > 0

    then replace(string,substring(string,patindex('%[0-9]%',string),1),'#')

    when patindex('%[a-zA-z]%',string) > 0

    then replace(string,substring(string,patindex('%[a-zA-z]%',string),1),'@')

    end

    as varchar(500))

    from cte

    where patindex('%[0-9a-zA-Z]%',string) > 0

    )

    select id, replace(string,'@','A') string from

    (select *,row_number()over(partition by id order by nbr desc)rnk from cte)d

    where rnk=1

  • Your pick:

    DECLARE @TestStr VARCHAR(20) = ' Q2ERY56,920 TYEU';

    SELECT @TestStr;

    WITH eTally(n) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM sys.all_columns a CROSS JOIN sys.all_columns b)

    SELECT

    NewString = STUFF((SELECT '' + NewChar FROM

    (SELECT TOP (LEN(@TestStr))

    n,

    CASE WHEN SUBSTRING(@TestStr,n,1) NOT LIKE '[^0-9]' THEN '#' ELSE 'A' END NewChar

    FROM

    eTally)dt

    ORDER BY n

    FOR XML PATH(''),TYPE).value('.','varchar(max)'),1,0,'');

    GO

    DECLARE @TestStr VARCHAR(20) = ' Q2ERY56,920 TYEU';

    SELECT @TestStr;

    WITH eTally(n) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM sys.all_columns a CROSS JOIN sys.all_columns b)

    SELECT

    NewString = STUFF((SELECT '' + NewChar FROM

    (SELECT TOP (LEN(@TestStr))

    n,

    CASE WHEN SUBSTRING(@TestStr,n,1) LIKE '[0-9]' THEN '#'

    WHEN SUBSTRING(@TestStr,n,1) LIKE '[A-Za-z]' THEN 'A'

    ELSE SUBSTRING(@TestStr,n,1) END NewChar

    FROM

    eTally)dt

    ORDER BY n

    FOR XML PATH(''),TYPE).value('.','varchar(max)'),1,0,'');

  • declare @t table(id int, string varchar(500))

    insert @t values (1,'abcABC,0123456789~!@'),(2,'123abcdefghijklmnopqrstuvwzyz');

    with cte1 as

    (

    select id,

    0 nbr,

    cast(string as varchar(500)) string

    from @t

    union all

    select id,

    nbr + 1,

    cast(replace(string,nbr,'#') as varchar(500))

    from cte1

    where nbr < 10

    ),

    cte2 as

    (

    select id,

    65 nbr,

    cast(string as varchar(500)) string

    from (select *, row_number()over(partition by id

    order by nbr desc)rnk

    from cte1

    )d

    where rnk = 1

    union all

    select id,

    nbr +1,

    cast(replace(string,char(nbr),'_') as varchar(500))

    from cte2

    where nbr < 65+26+1

    )

    select id, replace(string,'_','A') string

    from (select *, row_number() over(partition by id order by nbr desc) rnk from cte2)d

    where rnk = 1

  • zombieisdead2020 (1/3/2013)


    declare @t table(id int, string varchar(500))

    insert @t values (1,'abcABC,0123456789~!@'),(2,'123abcdefghijklmnopqrstuvwzyz');

    with cte1 as

    (

    select id,

    0 nbr,

    cast(string as varchar(500)) string

    from @t

    union all

    select id,

    nbr + 1,

    cast(replace(string,nbr,'#') as varchar(500))

    from cte1

    where nbr < 10

    ),

    cte2 as

    (

    select id,

    65 nbr,

    cast(string as varchar(500)) string

    from (select *, row_number()over(partition by id

    order by nbr desc)rnk

    from cte1

    )d

    where rnk = 1

    union all

    select id,

    nbr +1,

    cast(replace(string,char(nbr),'_') as varchar(500))

    from cte2

    where nbr < 65+26+1

    )

    select id, replace(string,'_','A') string

    from (select *, row_number() over(partition by id order by nbr desc) rnk from cte2)d

    where rnk = 1

    The recursive CTE may not scale well as the length of the strings increase. Both sets of options really need to be tested to determine which is better solution.

  • The recursive CTE may not scale well as the length of the strings increase. Both sets of options really need to be tested to determine which is better solution.

    My recursive CTE solutions is not depended to length of any string.

  • I just love having something in my toolbox to deal with stuff like this. Refer to the 4th link in my signature to find PatternSplitCM and then try this:

    ;WITH

    TestStrings (ItemNo, TestStr) AS (

    SELECT 1, 'Q2ERY56920TYEU_$%' UNION ALL SELECT 2, 'I LOVE SSC 100% IN 2013'),

    SplitStrings AS (

    SELECT ItemNo, Item1=a.ItemNumber, Item2=b.ItemNumber

    ,Item=CASE WHEN a.Matched = 1 THEN REPLICATE('#', LEN(a.Item))

    WHEN b.Matched = 1 THEN REPLICATE('A', LEN(b.Item))

    ELSE b.Item END

    FROM TestStrings

    CROSS APPLY PatternSplitCM(TestStr, '[0-9]') a

    CROSS APPLY PatternSplitCM(a.Item, '[A-Za-z]') b)

    SELECT (

    SELECT Item + ''

    FROM SplitStrings b

    WHERE a.ItemNo = b.ItemNo

    ORDER BY Item1, Item2

    FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)')

    FROM SplitStrings a

    GROUP BY ItemNo

    The article was actually based on solving a similar problem, which you can read about therein.


    My mantra: No loops! No CURSORs! No RBAR! Hoo-uh![/I]

    My thought question: Have you ever been told that your query runs too fast?

    My advice:
    INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
    The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.

    Need to UNPIVOT? Why not CROSS APPLY VALUES instead?[/url]
    Since random numbers are too important to be left to chance, let's generate some![/url]
    Learn to understand recursive CTEs by example.[/url]
    [url url=http://www.sqlservercentral.com/articles/St

  • zombieisdead2020 (1/3/2013)


    The recursive CTE may not scale well as the length of the strings increase. Both sets of options really need to be tested to determine which is better solution.

    My recursive CTE solutions is not depended to length of any string.

    I didn't say it was dependent on the length of any string. I said it MAY NOT scale well as the length of the strings increased and that tests should be run to determine how well each of the solutions work. Nothing more, nothing less.

  • Thanks very much for all the replies. I greatly appreciate them.

  • Those embedded REPLACEs are looking more tempting now, huh? 🙂

    SQL DBA,SQL Server MVP(07, 08, 09) "It's a dog-eat-dog world, and I'm wearing Milk-Bone underwear." "Norm", on "Cheers". Also from "Cheers", from "Carla": "You need to know 3 things about Tortelli men: Tortelli men draw women like flies; Tortelli men treat women like flies; Tortelli men's brains are in their flies".

Viewing 14 posts - 1 through 13 (of 13 total)

You must be logged in to reply to this topic. Login to reply