SQL Server:将所有UPPER案例设置为正确的案例/标题案例

问题描述 投票:79回答:19

我有一个表作为所有UPPER CASE导入,我想把它变成正确的案例。你们有什么脚本用来完成这个?

sql sql-server uppercase title-case
19个回答
70
投票

这是一个可以解决问题的UDF ......

create function ProperCase(@Text as varchar(8000))
returns varchar(8000)
as
begin
  declare @Reset bit;
  declare @Ret varchar(8000);
  declare @i int;
  declare @c char(1);

  if @Text is null
    return null;

  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 @c like '[a-zA-Z]' then 0 else 1 end,
      @i = @i + 1
  return @Ret
end

您仍然必须使用它来更新您的数据。


1
投票

保持对异常的查找以照顾冯·诺依曼,麦凯恩,德古兹曼和约翰逊 - 史密斯是有意义的。


0
投票

我想你会发现以下更有效:

IF OBJECT_ID('dbo.ProperCase') IS NOT NULL
    DROP FUNCTION dbo.ProperCase
GO
CREATE FUNCTION dbo.PROPERCASE (
    @str VARCHAR(8000))
RETURNS VARCHAR(8000)
AS
BEGIN
    SET @str = ' ' + @str
    SET @str = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( @str, ' a', ' A'), ' b', ' B'), ' c', ' C'), ' d', ' D'), ' e', ' E'), ' f', ' F'), ' g', ' G'), ' h', ' H'), ' i', ' I'), ' j', ' J'), ' k', ' K'), ' l', ' L'), ' m', ' M'), ' n', ' N'), ' o', ' O'), ' p', ' P'), ' q', ' Q'), ' r', ' R'), ' s', ' S'), ' t', ' T'), ' u', ' U'), ' v', ' V'), ' w', ' W'), ' x', ' X'), ' y', ' Y'), ' z', ' Z')
    RETURN RIGHT(@str, LEN(@str) - 1)
END
GO

可以将replace语句直接剪切并粘贴到SQL查询中。这是非常难看的,但是通过将@str替换为您感兴趣的列,您将不会像使用这样发布的udf那样为隐式游标付出代价。我发现即使使用我的UDF它也更有效率。

哦,而不是手动生成替换语句使用此:

-- Code Generator for expression
DECLARE @x  INT,
    @c  CHAR(1),
    @sql    VARCHAR(8000)
SET @x = 0
SET @sql = '@str' -- actual variable/column you want to replace
WHILE @x < 26
BEGIN
    SET @c = CHAR(ASCII('a') + @x)
    SET @sql = 'REPLACE(' + @sql + ', '' ' + @c+  ''', '' ' + UPPER(@c) + ''')'
    SET @x = @x + 1
END
PRINT @sql

无论如何,它取决于行数。我希望你能做到s / \ b([a-z])/ uc $ 1 /,但是哦,我们使用我们拥有的工具。

注意你必须使用它,因为你必须使用它.... SELECT dbo.ProperCase(LOWER(column))因为列是大写的。它实际上在我的5000个条目(甚至不到一秒)的表上工作得非常快,即使是较低的条目。

为了回应关于国际化的一系列评论,我提出了以下实现,它只处理依赖于SQL Server上层和下层实现的每个ascii字符。请记住,我们在这里使用的变量是VARCHAR,这意味着它们只能保存ASCII值。要使用更多国际字母表,您必须使用NVARCHAR。逻辑是相似的,但你需要使用UNICODE和NCHAR代替ASCII和CHAR,而替换语句会更大......

-- Code Generator for expression
DECLARE @x  INT,
    @c  CHAR(1),
    @sql    VARCHAR(8000),
    @count  INT
SEt @x = 0
SET @count = 0
SET @sql = '@str' -- actual variable you want to replace
WHILE @x < 256
BEGIN
    SET @c = CHAR(@x)
    -- Only generate replacement expression for characters where upper and lowercase differ
    IF @x = ASCII(LOWER(@c)) AND @x != ASCII(UPPER(@c))
    BEGIN
        SET @sql = 'REPLACE(' + @sql + ', '' ' + @c+  ''', '' ' + UPPER(@c) + ''')'
        SET @count = @count + 1
    END
    SET @x = @x + 1
END
PRINT @sql
PRINT 'Total characters substituted: ' + CONVERT(VARCHAR(255), @count)

基本上我的方法的前提是交易预计算的效率。完整的ASCII实现如下:

IF OBJECT_ID('dbo.ProperCase') IS NOT NULL
    DROP FUNCTION dbo.ProperCase
GO
CREATE FUNCTION dbo.PROPERCASE (
    @str VARCHAR(8000))
RETURNS VARCHAR(8000)
AS
BEGIN
    SET @str = ' ' + @str
SET @str =     REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@str, ' a', ' A'), ' b', ' B'), ' c', ' C'), ' d', ' D'), ' e', ' E'), ' f', ' F'), ' g', ' G'), ' h', ' H'), ' i', ' I'), ' j', ' J'), ' k', ' K'), ' l', ' L'), ' m', ' M'), ' n', ' N'), ' o', ' O'), ' p', ' P'), ' q', ' Q'), ' r', ' R'), ' s', ' S'), ' t', ' T'), ' u', ' U'), ' v', ' V'), ' w', ' W'), ' x', ' X'), ' y', ' Y'), ' z', ' Z'), ' š', ' Š'), ' œ', ' Œ'), ' ž', ' Ž'), ' à', ' À'), ' á', ' Á'), ' â', ' Â'), ' ã', ' Ã'), ' ä', ' Ä'), ' å', ' Å'), ' æ', ' Æ'), ' ç', ' Ç'), ' è', ' È'), ' é', ' É'), ' ê', ' Ê'), ' ë', ' Ë'), ' ì', ' Ì'), ' í', ' Í'), ' î', ' Î'), ' ï', ' Ï'), ' ð', ' Ð'), ' ñ', ' Ñ'), ' ò', ' Ò'), ' ó', ' Ó'), ' ô', ' Ô'), ' õ', ' Õ'), ' ö', ' Ö'), ' ø', ' Ø'), ' ù', ' Ù'), ' ú', ' Ú'), ' û', ' Û'), ' ü', ' Ü'), ' ý', ' Ý'), ' þ', ' Þ'), ' ÿ', ' Ÿ')
    RETURN RIGHT(@str, LEN(@str) - 1)
END
GO

0
投票

回去获取非大写数据是否为时已晚?

von Neumann's,McCain's,DeGuzman's和你客户群的Johnson-Smith可能不喜欢你的处理结果......

另外,我猜这是为了一次性升级数据?导出,过滤/修改以及将更正的名称重新导入数据库可能更容易,然后您可以使用非SQL方法命名修复...


0
投票

这是我在SQLTeam.com Forums @ http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=47718上找到的另一个变体

create FUNCTION PROPERCASE
(
--The string to be converted to proper case
@input varchar(8000)
)
--This function returns the proper case string of varchar type
RETURNS varchar(8000)
AS
BEGIN
IF @input IS NULL
BEGIN
--Just return NULL if input string is NULL
RETURN NULL
END

--Character variable declarations
DECLARE @output varchar(8000)
--Integer variable declarations
DECLARE @ctr int, @len int, @found_at int
--Constant declarations
DECLARE @LOWER_CASE_a int, @LOWER_CASE_z int, @Delimiter char(3), @UPPER_CASE_A int, @UPPER_CASE_Z int

--Variable/Constant initializations
SET @ctr = 1
SET @len = LEN(@input)
SET @output = ''
SET @LOWER_CASE_a = 97
SET @LOWER_CASE_z = 122
SET @Delimiter = ' ,-'
SET @UPPER_CASE_A = 65
SET @UPPER_CASE_Z = 90

WHILE @ctr <= @len
BEGIN
--This loop will take care of reccuring white spaces
WHILE CHARINDEX(SUBSTRING(@input,@ctr,1), @Delimiter) > 0
BEGIN
SET @output = @output + SUBSTRING(@input,@ctr,1)
SET @ctr = @ctr + 1
END

IF ASCII(SUBSTRING(@input,@ctr,1)) BETWEEN @LOWER_CASE_a AND @LOWER_CASE_z
BEGIN
--Converting the first character to upper case
SET @output = @output + UPPER(SUBSTRING(@input,@ctr,1))
END
ELSE
BEGIN
SET @output = @output + SUBSTRING(@input,@ctr,1)
END

SET @ctr = @ctr + 1

WHILE CHARINDEX(SUBSTRING(@input,@ctr,1), @Delimiter) = 0 AND (@ctr <= @len)
BEGIN
IF ASCII(SUBSTRING(@input,@ctr,1)) BETWEEN @UPPER_CASE_A AND @UPPER_CASE_Z
BEGIN
SET @output = @output + LOWER(SUBSTRING(@input,@ctr,1))
END
ELSE
BEGIN
SET @output = @output + SUBSTRING(@input,@ctr,1)
END
SET @ctr = @ctr + 1
END

END
RETURN @output
END



GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO

0
投票

我知道魔鬼在细节上(特别是在人们的个人数据方面),并且拥有适当大写的名字会非常好,但上述麻烦是为什么我们中间务实,时间敏感的人使用以下内容:

SELECT UPPER('Put YoUR O'So oddLy casED McWeird-nAme von rightHERE here')

根据我的经验,人们可以很好地看到他们的名字......即使是在句子的一半时间。

参考:俄罗斯人使用铅笔!


0
投票

刚刚了解了InitCap()

以下是一些示例代码:

SELECT ID
      ,InitCap(LastName ||', '|| FirstName ||' '|| Nvl(MiddleName,'')) AS RecipientName
FROM SomeTable

0
投票

这在SSMS中有效:

Select Jobtitle,
concat(Upper(LEFT(jobtitle,1)), SUBSTRING(jobtitle,2,LEN(jobtitle))) as Propercase
From [HumanResources].[Employee]

0
投票

在@Richard Sayakanit的回答中借用和改进。这可以处理多个单词。像他的回答一样,这不使用任何UDF,只使用内置函数(STRING_SPLITSTRING_AGG)而且速度非常快。 STRING_AGG需要SQL Server 2017,但你总是可以使用STUFF/XML技巧。不会处理每个例外,但可以满足许多要求。

SELECT StateName = 'North Carolina' 
INTO #States
UNION ALL
SELECT 'Texas'


;WITH cteData AS 
(
    SELECT 
        UPPER(LEFT(value, 1)) +
            LOWER(RIGHT(value, LEN(value) - 1)) value, op.StateName
    FROM   #States op
    CROSS APPLY STRING_SPLIT(op.StateName, ' ') AS ss
)
SELECT 
    STRING_AGG(value, ' ')
FROM cteData c 
GROUP BY StateName

0
投票

如果您知道所有数据只是一个单词,那么这是一个解决方案。首先将列更新为全部更低,然后运行以下命令

    update tableName set columnName = 
    upper(SUBSTRING(columnName, 1, 1)) + substring(columnName, 2, len(columnName)) from tableName

0
投票

对@ Galwegian的回答略有修改 - 例如St Elizabeth's进入St Elizabeth'S

这种修改将撇号保持为小写,其中s位于提供的字符串的末尾,或者s后跟空格(并且仅在这些情况下)。

create function properCase(@text as varchar(8000))
returns varchar(8000)
as
begin
    declare @reset int;
    declare @ret varchar(8000);
    declare @i int;
    declare @c char(1);
    declare @d char(1);

    if @text is null
    return null;

    select @reset = 1, @i = 1, @ret = '';

    while (@i <= len(@text))
    select
        @c = substring(@text, @i, 1),
        @d = substring(@text, @i+1, 1),
        @ret = @ret + case when @reset = 1 or (@reset=-1 and @c!='s') or (@reset=-1 and @c='s' and @d!=' ') then upper(@c) else lower(@c) end,
        @reset = case when @c like '[a-za-z]' then 0 when @c='''' then -1 else 1 end,
        @i = @i + 1
    return @ret
end

事实证明:

  • st elizabeth's进入St Elizabeth's
  • o'keefe进入O'Keefe
  • o'sullivan进入O'Sullivan

其他人的评论认为不同的解决方案对于非英语输入更可取。


97
投票

这个功能:

  • “正确案例”所有由白色空间划分的“大写”字样
  • 单独留下“小写字”
  • 即使对于非英文字母也能正常工作
  • 是可移植的,因为它不使用最新SQL Server版本的花哨功能
  • 可以轻松更改为使用NCHAR和NVARCHAR获得unicode支持,以及您认为合适的任何参数长度
  • 可以配置空白区域定义
CREATE FUNCTION ToProperCase(@string VARCHAR(255)) RETURNS VARCHAR(255)
AS
BEGIN
  DECLARE @i INT           -- index
  DECLARE @l INT           -- input length
  DECLARE @c NCHAR(1)      -- current char
  DECLARE @f INT           -- first letter flag (1/0)
  DECLARE @o VARCHAR(255)  -- output string
  DECLARE @w VARCHAR(10)   -- characters considered as white space

  SET @w = '[' + CHAR(13) + CHAR(10) + CHAR(9) + CHAR(160) + ' ' + ']'
  SET @i = 1
  SET @l = LEN(@string)
  SET @f = 1
  SET @o = ''

  WHILE @i <= @l
  BEGIN
    SET @c = SUBSTRING(@string, @i, 1)
    IF @f = 1 
    BEGIN
     SET @o = @o + @c
     SET @f = 0
    END
    ELSE
    BEGIN
     SET @o = @o + LOWER(@c)
    END

    IF @c LIKE @w SET @f = 1

    SET @i = @i + 1
  END

  RETURN @o
END

结果:

dbo.ToProperCase('ALL UPPER CASE and    SOME lower ÄÄ ÖÖ ÜÜ ÉÉ ØØ ĈĈ ÆÆ')
-----------------------------------------------------------------
All Upper Case and      Some lower Ää Öö Üü Éé Øø Cc Ææ

35
投票
UPDATE titles
  SET title =
      UPPER(LEFT(title, 1)) +
        LOWER(RIGHT(title, LEN(title) - 1))

http://sqlmag.com/t-sql/how-title-case-column-value


17
投票

如果您可以在SQL Server中启用CLR(需要2005或更高版本),那么您可以使用create a CLR function来使用TextInfo.ToTitleCase built-in function,这样您就可以在几行代码中创建一种文化感知方式。


8
投票

我在游戏中有点晚了,但我相信它更实用,它适用于任何语言,包括俄语,德语,泰语,越南语等。它会在'或 - 之后做任何大写。或(或)或空间(显然:)。

CREATE FUNCTION [dbo].[fnToProperCase]( @name nvarchar(500) )
RETURNS nvarchar(500)
AS
BEGIN
declare @pos    int = 1
      , @pos2   int

if (@name <> '')--or @name = lower(@name) collate SQL_Latin1_General_CP1_CS_AS or @name = upper(@name) collate SQL_Latin1_General_CP1_CS_AS)
begin
    set @name = lower(rtrim(@name))
    while (1 = 1)
    begin
        set @name = stuff(@name, @pos, 1, upper(substring(@name, @pos, 1)))
        set @pos2 = patindex('%[- ''.)(]%', substring(@name, @pos, 500))
        set @pos += @pos2
        if (isnull(@pos2, 0) = 0 or @pos > len(@name))
            break
    end
end

return @name
END
GO

7
投票

我知道这是在这个帖子中的后期但是,值得一看。这个功能对我有用。所以想分享它。

CREATE FUNCTION [dbo].[fnConvert_TitleCase] (@InputString VARCHAR(4000) )
RETURNS VARCHAR(4000)
AS
BEGIN
DECLARE @Index INT
DECLARE @Char CHAR(1)
DECLARE @OutputString VARCHAR(255)

SET @OutputString = LOWER(@InputString)
SET @Index = 2
SET @OutputString = STUFF(@OutputString, 1, 1,UPPER(SUBSTRING(@InputString,1,1)))

WHILE @Index <= LEN(@InputString)
BEGIN
    SET @Char = SUBSTRING(@InputString, @Index, 1)
    IF @Char IN (' ', ';', ':', '!', '?', ',', '.', '_', '-', '/', '&','''','(')
    IF @Index + 1 <= LEN(@InputString)
BEGIN
    IF @Char != ''''
    OR
    UPPER(SUBSTRING(@InputString, @Index + 1, 1)) != 'S'
    SET @OutputString =
    STUFF(@OutputString, @Index + 1, 1,UPPER(SUBSTRING(@InputString, @Index + 1, 1)))
END
    SET @Index = @Index + 1
END

RETURN ISNULL(@OutputString,'')
END

测试电话:

select dbo.fnConvert_TitleCase(Upper('ÄÄ ÖÖ ÜÜ ÉÉ ØØ ĈĈ ÆÆ')) as test
select dbo.fnConvert_TitleCase(upper('Whatever the mind of man can conceive and believe, it can achieve. – Napoleon hill')) as test

结果:


3
投票

如果您在SSIS中导入已混合的数据并且需要使用正确的大小写对列进行查找,您会注意到查找在源混合且查找源正确的情况下失败。您还会注意到,对于派生列,您无法使用右侧和左侧函数SSIS for SQL Server 2008r2。这是一个适合我的解决方案:

UPPER(substring(input_column_name,1,1)) + LOWER(substring(input_column_name, 2, len(input_column_name)-1))

1
投票

我上面发布的链接是解决主要问题的一个很好的选择:我们永远不能以编程方式解释所有情况(Smith-Jones,von Haussen,John Smith M.D.),至少不是优雅的方式。 Tony介绍了异常/中断字符的概念来处理这些情况。无论如何,基于Cervo的想法(在空格之前的所有较低的字符上面),替换语句可以包含在基于单个表的替换中。实际上,任何低/高字符组合都可以插入@alpha并且语句不会改变:

declare @str    nvarchar(8000)
declare @alpha  table (low nchar(1), up nchar(1))


set @str = 'ALL UPPER CASE and    SOME lower ÄÄ ÖÖ ÜÜ ÉÉ ØØ ĈĈ ÆÆ'

-- stage the alpha (needs number table)
insert into @alpha
    -- A-Z / a-z
    select      nchar(n+32),
                nchar(n)
    from        dbo.Number
    where       n between 65 and 90 or
                n between 192 and 223

-- append space at start of str
set @str = lower(' ' + @str)

-- upper all lower case chars preceded by space
select  @str = replace(@str, ' ' + low, ' ' + up) 
from    @Alpha

select @str

1
投票

这是一个使用序列或数字表而不是循环的版本。您可以修改WHERE子句以适应您何时将字符转换为大写的个人规则。我刚刚包含了一个简单的集合,它将大写任何字母,除了撇号之外都是非字母。这有点意味着123apple会在“a”上匹配,因为“3”不是一个字母。如果你只想要空格(空格,制表符,回车符,换行符),你可以用'[^a-z]'替换模式'[' + Char(32) + Char(9) + Char(13) + Char(10) + ']'


CREATE FUNCTION String.InitCap( @string nvarchar(4000) ) RETURNS nvarchar(4000) AS
BEGIN

-- 1. Convert all letters to lower case
    DECLARE @InitCap nvarchar(4000); SET @InitCap = Lower(@string);

-- 2. Using a Sequence, replace the letters that should be upper case with their upper case version
    SELECT @InitCap = Stuff( @InitCap, n, 1, Upper( SubString( @InitCap, n, 1 ) ) )
    FROM (
        SELECT (1 + n1.n + n10.n + n100.n + n1000.n) AS n
        FROM       (SELECT 0 AS n UNION SELECT    1 UNION SELECT    2 UNION SELECT    3 UNION SELECT    4 UNION SELECT    5 UNION SELECT    6 UNION SELECT    7 UNION SELECT    8 UNION SELECT    9) AS    n1
        CROSS JOIN (SELECT 0 AS n UNION SELECT   10 UNION SELECT   20 UNION SELECT   30 UNION SELECT   40 UNION SELECT   50 UNION SELECT   60 UNION SELECT   70 UNION SELECT   80 UNION SELECT   90) AS   n10
        CROSS JOIN (SELECT 0 AS n UNION SELECT  100 UNION SELECT  200 UNION SELECT  300 UNION SELECT  400 UNION SELECT  500 UNION SELECT  600 UNION SELECT  700 UNION SELECT  800 UNION SELECT  900) AS  n100
        CROSS JOIN (SELECT 0 AS n UNION SELECT 1000 UNION SELECT 2000 UNION SELECT 3000)                                                                                                             AS n1000
        ) AS Sequence
    WHERE 
        n BETWEEN 1 AND Len( @InitCap )
    AND SubString( @InitCap, n, 1 ) LIKE '[a-z]'                 /* this character is a letter */
    AND (
        n = 1                                                    /* this character is the first `character` */
        OR SubString( @InitCap, n-1, 1 ) LIKE '[^a-z]'           /* the previous character is NOT a letter */
        )
    AND (
        n < 3                                                    /* only test the 3rd or greater characters for this exception */
        OR SubString( @InitCap, n-2, 3 ) NOT LIKE '[a-z]''[a-z]' /* exception: The pattern <letter>'<letter> should not capatolize the letter following the apostrophy */
        )

-- 3. Return the modified version of the input
    RETURN @InitCap

END
© www.soinside.com 2019 - 2024. All rights reserved.