Reputation: 575
I need to write a function that removes all leading zero's from a varchar column. Example: 0300 has to become 300 and A0300 has to become A300. The first one is quit easy, but I can't get the second one to work (A0300-> A300). Could anyone point me in the right direction?
Upvotes: 0
Views: 63
Reputation: 15852
The festering code below demonstrates one way to walk through the strings with a trivial state machine for each and parse out the evil zeroes. To see what is happening internally you can switch select
s after the CTE.
-- Sample data.
declare @Samples as Table ( SampleId Int Identity, Sample VarChar(100) );
insert into @Samples ( Sample ) values
( '0300' ), ( 'A0300' ), ( 'zer0' ), ( '0' ), ( '000' ), ( '00000Q050098' );
select * from @Samples;
-- Fiendish thingy.
declare @False as Bit = 0, @True as Bit = 1;
with
Characters as (
select SampleId, Sample, 1 as Position, Substring( Sample, 1, 1 ) as Character,
case when Substring( Sample, 1, 1 ) = '0' then @True else @False end as IsZero,
case when Substring( Sample, 1, 1 ) = '0' then @True else @False end as FirstZeroes
from @Samples
union all
select SampleId, Sample, Position + 1, Substring( Sample, Position + 1, 1 ),
case when Substring( Sample, Position + 1, 1 ) = '0' then @True else @False end,
case
when FirstZeroes is NULL then NULL -- We're done with this string.
when FirstZeroes = @True and Substring( Sample, Position + 1, 1 ) <> '0' then NULL -- We just finished with this string.
when Substring( Sample, Position + 1, 1 ) = '0' then @True -- We're (still) going with this string.
else @False end
from Characters
where Position < Len( Sample ) )
-- select * from Characters order by SampleId, Position; -- Use this statement to see the intermediate results.
select C.SampleId, C.Sample,
Coalesce( Stuff( ( select Character from Characters where SampleId = C.SampleId and ( FirstZeroes = 0 or FirstZeroes is NULL ) order by Position for XML path(''), type).value('.[1]', 'VarChar(max)' ), 1, 0, '' ), '' ) as DeZeroed
from Characters as C
group by SampleId, Sample
Upvotes: 0
Reputation: 469
On older versions where PATINDEX does not work, or if PATINDEX is too slow:
Do a case and use LIKE '[0-9]' / NOT LIKE '[0-9]' to find the right splitting point - assuming the know the max length of your string so that you can prepare as many cases as needed. You find the right the right character number where the number starts, and cast the right part as INT to eliminate the leading 0, then cast the result as VARCHAR to re-aggregate with your leading letter(s).
Would make something like below: SELECT CASE WHEN LEFT (columnname,1) NOT LIKE '[0-9]' AND SUBSTRING (columnname,2,1) LIKE '[0-9]' THEN LEFT (columnname,1) + CAST (CAST (SUBSTRING (2,(LEN(columnname)-2) ) AS INT) AS VARCHAR(25)) WHEN LEFT (columnname,2) NOT LIKE '[0-9]' AND SUBSTRING (columnname,3,1) .... END
You should trim the spaces with LTRIM(RTRIM(columnname)) if you're not sure of the leading/trailing spaces, since we are counting the number of characters it may be more reliable.
Upvotes: 0
Reputation: 997
WITH test AS
(
SELECT 'A0300' AS code
UNION
SELECT '0300'
),
strip AS (
SELECT code, SUBSTRING(code, PATINDEX('%[0-9]%', code), LEN(code)) AS number
from test
)
select REPLACE(code, number, CAST(number as INT))
FROM strip
Upvotes: 1