Reputation: 43
I have a table of names that I am trying to convert from UPPERCASE to Proper Case. And the below code does almost exactly what I am. When I was testing it out I noticed that I had folks who had Roman Numerals in their name, Mc* and O'* in the table. Naturally the query converted any multiple Roman Numeral into Iv like it was supposed to and any MCDONALDS or O'DANIEL were converted into Mcdonalds and O'daniel. I was trying to figure out how to make a clean change to this function so I can run my update query but I'm still peacemilling my SQL knowledge together in off hours. Any help/suggestions would be much appreciated. I did a google search and found several examples but the ones I tried didn't work. The amount of corrections I would have to do is relatively minor (17 corrections out of 1000 row table), but I'd like to try and tidy it up to limit as many human errors as possible.
Thank you in advance for your help.
CREATE FUNCTION [dbo].[f_ProperCase]
(@Text as varchar(80))
RETURNS varchar(80) as
BEGIN
DECLARE @Reset bit
DECLARE @Ret varchar(80)
DECLARE @i int
DECLARE @c char(1)
SELECT @Reset = 1, @i=1, @Ret = ''
WHILE @i <= LEN(@Text)
SELECT @c= SUBSTRING(@Text,@i,1),
@Ret = @Ret + CASE WHEN @Reset=1 THEN UPPER(@c) ELSE LOWER(@c) END,
@Reset= CASE WHEN
CASE WHEN SUBSTRING(@Text,@i-4,5) like '_[a-z] [DOL]''' THEN 1
WHEN SUBSTRING(@Text,@i-4,5) like '_[a-z] [D][I]' THEN 1
WHEN SUBSTRING(@Text,@i-4,5) like '_[a-z] [M][C]' THEN 1
WHEN SUBSTRING(@Text,@i-4,5) like '_[a-z] [M][c][*]' THEN 1 --Convert MCDONALD to McDonald
WHEN SUBSTRING(@Text,@I-4,5) like '_[a-z] [O][''][*]' THEN 1 --Convert O'DONNEL to O'Donnel
ELSE 0
END = 1
THEN 1
ELSE CASE WHEN @c like '[a-zA-Z]' or @c in ('''') THEN 0
ELSE 1
END
END,
@i = @i +1
RETURN @Ret
end
Upvotes: 4
Views: 6392
Reputation: 1
I tweaked some to handle suffixes being included in the name. This handled almost anything I threw at it. We sometimes had hyphenated names as well as periods after some suffixes. I know handling from I-IX was overkill, but was easy enough to add the X to the V check.
ALTER FUNCTION dbo.udf_ProperCase
(@Text as varchar(1024))
RETURNS varchar(1024)
AS
/*
Created to ProperCase most common LastName (Mc/Mac/O'/D'/L') and handle I(first)-IX(nineteenth) suffixes
Original Code: https://stackoverflow.com/questions/22923616/sql-proper-case-function-query-refinement
SELECT dbo.udf_ProperCase('iitest demetrii mcdonald o''neil victor second 2nd ii iii iv v vi vii viii ix x xi test')
*/
BEGIN
DECLARE @Reset bit
DECLARE @Ret varchar(1024)
DECLARE @i int
DECLARE @c char(1)
DECLARE @Text1 varchar(1025)
SELECT @Reset = 1, @i=1, @Ret = '', @Text1 = ' ' + @Text + ' ' --Ensure one space before to make first char upper and after to handle suffixes
--Loop through each character, comparing prior/next to determine if need to handle
WHILE @i <= LEN(@Text1)
BEGIN
SELECT
@c= SUBSTRING(@Text1,@i,1)
,@Ret = @Ret + CASE WHEN @Reset=1 THEN UPPER(@c) ELSE LOWER(@c) END
,@Reset= CASE
WHEN
CASE
WHEN SUBSTRING(@Text1,@i-2,3) like '[ -][DdOoLl][''`]' THEN 1 --Names (including hyphenated) beginning with D/O/L
WHEN SUBSTRING(@Text1,@i-2,4) like ' [Mm][cC][a-zA-Z]' THEN 1 --Names with Mc
WHEN SUBSTRING(@Text1,@i-3,5) like ' [Mm][Aa][cC][a-zA-Z]' THEN 1 --Names with Mac
WHEN SUBSTRING(@Text1,@i-1,4) like ' [Ii][Ii][ .]' THEN 1 --Handle II (include ending with Space or period)
WHEN SUBSTRING(@Text1,@i-1,5) like ' [Ii][Ii][Ii][ .]' THEN 1 --Handle III
WHEN SUBSTRING(@Text1,@i-2,4) like ' [Ii][Ii][ .]' THEN 1 --Handle II
WHEN SUBSTRING(@Text1,@i-2,5) like ' [Ii][Ii][Ii][ .]' THEN 1 --Handle III
WHEN SUBSTRING(@Text1,@i-3,4) like ' [Ii][Ii][ .]' THEN 1 --Handle II
WHEN SUBSTRING(@Text1,@i-3,5) like ' [Ii][Ii][Ii][ .]' THEN 1 --Handle III
WHEN SUBSTRING(@Text1,@i-1,4) like ' [Ii][VvXx][ .]' THEN 1 --Handle IV
WHEN SUBSTRING(@Text1,@i-1,4) like ' [VvXx][Ii][ .]' THEN 1 --Handle VI
WHEN SUBSTRING(@Text1,@i-1,5) like ' [VvXx][Ii][Ii][ .]' THEN 1 --Handle VII
WHEN SUBSTRING(@Text1,@i-1,6) like ' [VvXx][Ii][Ii][Ii][ .]' THEN 1 --Handle VIII
WHEN SUBSTRING(@Text1,@i-2,4) like ' [VvXx][Ii][ .]' THEN 1 --Handle VI
WHEN SUBSTRING(@Text1,@i-2,5) like ' [VvXx][Ii][Ii][ .]' THEN 1 --Handle VII
WHEN SUBSTRING(@Text1,@i-2,6) like ' [VvXx][Ii][Ii][Ii][ .]' THEN 1 --Handle VIII
WHEN SUBSTRING(@Text1,@i-3,4) like ' [VvXx][Ii][ .]' THEN 1 --Handle VI
WHEN SUBSTRING(@Text1,@i-3,5) like ' [VvXx][Ii][Ii][ .]' THEN 1 --Handle VII
WHEN SUBSTRING(@Text1,@i-3,6) like ' [VvXx][Ii][Ii][Ii][ .]' THEN 1 --Handle VIII
ELSE 0
END = 1 THEN 1
ELSE
CASE
WHEN @c like '[a-zA-Z`]' or @c in ('''') or @c like '[0-9]' THEN 0 --If any letter, single-quote or number, then keep next lowercase
ELSE 1 --Anything else (e.g. Space dash, And(&), etc. make next Upper-Case)
END
END
,@i = @i +1
END
RETURN stuff(@Ret, 1, 1, '')
END
GO
Upvotes: 0
Reputation: 10411
I would do it differently:
CREATE FUNCTION [dbo].[f_ProperCase]
(@Text as varchar(80))
RETURNS varchar(80) as
BEGIN
DECLARE @Reset bit
DECLARE @Ret varchar(80)
DECLARE @i int
DECLARE @c char(1)
DECLARE @Text1 varchar(81)
SELECT @Reset = 1, @i=1, @Ret = '', @Text1 = ' ' + @Text
WHILE @i <= LEN(@Text1)
SELECT @c= SUBSTRING(@Text1,@i,1),
@Ret = @Ret + CASE WHEN @Reset=1 THEN UPPER(@c) ELSE LOWER(@c) END,
@Reset= CASE WHEN
CASE WHEN SUBSTRING(@Text1,@i-2,3) like ' [DdOoLl]''' THEN 1
WHEN SUBSTRING(@Text1,@i-2,4) like ' [Mm][cC][a-zA-Z]' THEN 1
WHEN SUBSTRING(@Text1,@i-3,5) like ' [Mm][Aa][cC][a-zA-Z]' THEN 1
ELSE 0
END = 1
THEN 1
ELSE CASE WHEN @c like '[a-zA-Z]' or @c in ('''') THEN 0
ELSE 1
END
END,
@i = @i +1
RETURN stuff(@Ret, 1, 1, '')
end
This function supports O', L', D', as well as Mc, and Mac. The function is also converts from any case (not only the upper case) to the proper case
select dbo.f_ProperCase('CORMACK')
,dbo.f_ProperCase('Mcdonald ronald')
,dbo.f_ProperCase('o''hara')
| | | |
|---------|-----------------|--------|
| Cormack | McDonald Ronald | O'Hara |
Upvotes: 8