sqlsql-servert-sqlsql-server-2019

How to decrement a number in a character-separated string


I have strings in a SQL Server table column:

SequenceId
2-10-14
2-8-15
2-8-16
2-8-16
2-17-21
2-0-5

I have to reduce the last digits after hyphen by one (as shown here):

2-10-13
2-8-14
2-8-15
2-8-15
2-17-20
2-0-4

Any help?


Solution

  • Try this fugliness. While not recommended, it seems to work. A proper database design is what is needed, for obvious performance and coding issues. The Common Table Expression just sets up test data and is a great way to provide example data. You really only need to select the last "joined_back" but I included the separate parts for completeness. Adapted from this post and he should get any credit: https://stackoverflow.com/a/20369450/2543416

    with tbl(SequenceId) as (
      select '2-10-14' union all
      select '2-8-15' union all
      select '2-8-16' union all
      select '2-8-16' union all
      select '2-17-21' union all
      select '2-0-5'
    )
    select 
     LEFT(SequenceId, LEN(SequenceId) - CHARINDEX('-',REVERSE(SequenceId))+1) AS first_part,
     RIGHT(SequenceId, CHARINDEX('-',REVERSE(SequenceId))-1) AS second_part,
     RIGHT(SequenceId, CHARINDEX('-',REVERSE(SequenceId))-1) - 1 as decrement,
     LEFT(SequenceId, LEN(SequenceId) - CHARINDEX('-',REVERSE(SequenceId))+1) + cast(RIGHT(SequenceId, CHARINDEX('-',REVERSE(SequenceId))-1) - 1 as char(2)) as joined_back 
    from tbl;
    
    
    first_part  second_part decrement   joined_back
    2-10-       14          13          2-10-13
    2-8-        15          14          2-8-14
    2-8-        16          15          2-8-15
    2-8-        16          15          2-8-15
    2-17-       21          20          2-17-20
    2-0-        5           4           2-0-4 
    

    It could also be written like this which aids in troubleshooting:

    with tbl(SequenceId) as (
      select '2-10-14' union all
      select '2-8-15' union all
      select '2-8-16' union all
      select '2-8-16' union all
      select '2-17-21' union all
      select '2-0-5'  union all
      select null
    ),
    tbl_splitup(first_part, second_part, decrement) as (
      select LEFT(SequenceId, LEN(SequenceId) - CHARINDEX('-',REVERSE(SequenceId))+1),
        RIGHT(SequenceId, CHARINDEX('-',REVERSE(SequenceId))-1),
        RIGHT(SequenceId, CHARINDEX('-',REVERSE(SequenceId))-1) - 1 as decrement
      from tbl
    )
    -- select * from tbl_splitup
    select first_part + cast(decrement as char(2)) as joined_back 
    from tbl_splitup;