SQL适当案例函数查询细化
Posted
技术标签:
【中文标题】SQL适当案例函数查询细化【英文标题】:SQL Proper Case Function Query Refinement 【发布时间】:2014-05-20 08:34:09 【问题描述】:我有一个名称表,我正在尝试将其从大写转换为正确大小写。下面的代码几乎完全符合我的要求。当我测试它时,我注意到有些人的名字中有罗马数字,Mc* 和 O'* 在表中。自然地,该查询将任何多个罗马数字转换为 Iv,就像它应该做的那样,任何 MCDONALDS 或 O'DANIEL 都被转换为 Mcdonalds 和 O'daniel。我试图弄清楚如何对这个函数进行彻底的更改,以便我可以运行我的更新查询,但我仍然在下班时间将我的 SQL 知识和平磨合在一起。任何帮助/建议将不胜感激。我进行了谷歌搜索并找到了几个示例,但我尝试过的那些都不起作用。我必须做的更正量相对较小(1000 行表中的 17 次更正),但我想尝试整理它以尽可能减少人为错误。
提前感谢您的帮助。
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
【问题讨论】:
【参考方案1】:我调整了一些以处理名称中包含的后缀。这几乎处理了我扔给它的任何东西。我们有时在一些后缀之后有连字符的名称和句点。我知道从 I-IX 处理是多余的,但很容易将 X 添加到 V 检查。
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://***.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
【讨论】:
【参考方案2】:我会做不同的事情:
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
此功能支持O'、L'、D',以及Mc、Mac。该函数还可以从任何大小写(不仅是大写)转换为正确的大小写
SQL Fiddle
select dbo.f_ProperCase('CORMACK')
,dbo.f_ProperCase('Mcdonald ronald')
,dbo.f_ProperCase('o''hara')
| | | |
|---------|-----------------|--------|
| Cormack | McDonald Ronald | O'Hara |
【讨论】:
我只是在我的测试系统中厌倦了这个,它就像一个魅力。非常感谢你的帮助,Cha。 效果很好,唯一的问题是对于像“CORMACK”这样的名称,它将返回“CormacK” 太棒了,感谢您花时间更新,完美运行 有人在 mysql 中有这个工作吗?我的函数语法很弱,似乎无法让它工作。以上是关于SQL适当案例函数查询细化的主要内容,如果未能解决你的问题,请参考以下文章
LINQ 左外连接查询错误:OuterApply 没有适当的键
2021年大数据ELK(十六):Elasticsearch SQL(职位查询案例)
MySQL进阶8 分页查询(limit) - SQL查询语法顺序及大致结构- 子查询的3个经典案例