55

在 SQL Server 中将字符串中每个单词的首字母大写的最佳方法是什么。

4

18 回答 18

81

来自http://www.sql-server-helper.com/functions/initcap.aspx

CREATE FUNCTION [dbo].[InitCap] ( @InputString varchar(4000) ) 
RETURNS VARCHAR(4000)
AS
BEGIN

DECLARE @Index          INT
DECLARE @Char           CHAR(1)
DECLARE @PrevChar       CHAR(1)
DECLARE @OutputString   VARCHAR(255)

SET @OutputString = LOWER(@InputString)
SET @Index = 1

WHILE @Index <= LEN(@InputString)
BEGIN
    SET @Char     = SUBSTRING(@InputString, @Index, 1)
    SET @PrevChar = CASE WHEN @Index = 1 THEN ' '
                         ELSE SUBSTRING(@InputString, @Index - 1, 1)
                    END

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

    SET @Index = @Index + 1
END

RETURN @OutputString

END
GO

这里有一个更简单/更小的一个(但如果任何行没有空格,“无效的长度参数传递给 RIGHT 函数。”):

http://www.devx.com/tips/Tip/17608

于 2008-09-10T19:09:23.647 回答
5

作为表值函数:

CREATE FUNCTION dbo.InitCap(@v AS VARCHAR(MAX))
RETURNS TABLE
AS
RETURN 
WITH a AS (
    SELECT (
        SELECT UPPER(LEFT(value, 1)) + LOWER(SUBSTRING(value, 2, LEN(value))) AS 'data()'
        FROM string_split(@v, ' ')
        ORDER BY CHARINDEX(value,@v)
        FOR XML PATH (''), TYPE) ret)

SELECT CAST(a.ret AS varchar(MAX)) ret from a
GO

请注意,string_split需要COMPATIBILITY_LEVEL130。

于 2017-09-21T13:17:00.377 回答
3

如果您正在 Oracle/PLSQL 中寻找相同问题的答案,那么您可以使用函数 INITCAP。下面是一个来自表部门的属性dname的示例,它具有值('sales'、'management'、'production'、'development')。

SQL> select INITCAP(dname) from department;

INITCAP(DNAME)
--------------------------------------------------
Sales
Management
Production
Development
于 2018-10-27T20:03:45.260 回答
2

我已经使用了很长时间的一个变体是:

CREATE FUNCTION [widget].[properCase](@string varchar(8000)) RETURNS varchar(8000) AS
BEGIN   
    SET @string = LOWER(@string)
    DECLARE @i INT
    SET @i = ASCII('a')
    WHILE @i <= ASCII('z')
    BEGIN
        SET @string = REPLACE( @string, ' ' + CHAR(@i), ' ' + CHAR(@i-32))
        SET @i = @i + 1
    END
    SET @string = CHAR(ASCII(LEFT(@string, 1))-32) + RIGHT(@string, LEN(@string)-1)
    RETURN @string
END

如果您愿意,您可以轻松修改以处理除空格以外的项目之后的字符。

于 2008-09-10T19:55:00.527 回答
2

不使用循环的另一种解决方案 - 具有递归 CTE 的纯基于集合的方法

create function [dbo].InitCap (@value varchar(max))
returns varchar(max) as
begin

    declare
        @separator char(1) = ' ',
        @result varchar(max) = '';

    with r as (
        select value, cast(null as varchar(max)) [x], cast('' as varchar(max)) [char], 0 [no] from (select rtrim(cast(@value as varchar(max))) [value]) as j
        union all
        select right(value, len(value)-case charindex(@separator, value) when 0 then len(value) else charindex(@separator, value) end) [value]
        , left(r.[value], case charindex(@separator, r.value) when 0 then len(r.value) else abs(charindex(@separator, r.[value])-1) end ) [x]
        , left(r.[value], 1)
        , [no] + 1 [no]
        from r where value > '')

    select @result = @result +
    case
        when ascii([char]) between 97 and 122 
            then stuff(x, 1, 1, char(ascii([char])-32))
        else x
    end + @separator
    from r where x is not null;

    set @result = rtrim(@result);

    return @result;
end
于 2015-01-02T13:22:04.507 回答
2

这是最简单的一行代码。

select 
        LEFT(column, 1)+ lower(RIGHT(column, len(column)-1) )
     from [tablename]
于 2015-07-22T21:09:23.020 回答
1
;WITH StudentList(Name) AS (
      SELECT CONVERT(varchar(50), 'Carl-VAN')
UNION SELECT 'Dean o''brian'
UNION SELECT 'Andrew-le-Smith'
UNION SELECT 'Eddy thompson'
UNION SELECT 'BOBs-your-Uncle'
), Student AS (
    SELECT CONVERT(varchar(50), UPPER(LEFT(Name, 1)) + LOWER(SUBSTRING(Name, 2, LEN(Name)))) Name, 
           pos = PATINDEX('%[-'' ]%', Name)
    FROM StudentList
    UNION ALL
    SELECT CONVERT(varchar(50), LEFT(Name, pos) + UPPER(SUBSTRING(Name, pos + 1, 1)) + SUBSTRING(Name, pos + 2, LEN(Name))) Name, 
           pos = CASE WHEN PATINDEX('%[-'' ]%', RIGHT(Name, LEN(Name) - pos)) = 0 THEN 0 ELSE pos + PATINDEX('%[-'' ]%', RIGHT(Name, LEN(Name) - pos)) END
    FROM Student
    WHERE pos > 0
)
SELECT Name
FROM Student 
WHERE pos = 0
ORDER BY Name 

这将导致:

  • 安德鲁-勒-史密斯
  • Bobs-Your-Uncle
  • 卡尔-范
  • 迪恩·奥布莱恩
  • 艾迪汤普森

使用基于递归 CTE 集的查询应该胜过执行过程式 while 循环查询。在这里,对于更高级的示例,我还将我的单独设置为 3 个不同的字符 [-' ] 而不是 1。像我所做的那样使用 PATINDEX 可以让我查找许多字符。您也可以在单个字符上使用 CHARINDEX,并且此函数除了第三个参数 StartFromPosition,因此我可以进一步简单地将 pos 公式的第二部分递归到(假设一个空格): pos = CHARINDEX(' ', Name, pos + 1)。

于 2020-04-11T16:05:36.757 回答
0
BEGIN
DECLARE @string varchar(100) = 'asdsadsd asdad asd'
DECLARE @ResultString varchar(200) = ''
DECLARE @index int = 1
DECLARE @flag bit = 0
DECLARE @temp varchar(2) = ''
WHILE (@Index <LEN(@string)+1)
BEGIN
    SET @temp = SUBSTRING(@string, @Index-1, 1)
    --select @temp
    IF @temp = ' ' OR @index = 1
        BEGIN
            SET @ResultString = @ResultString + UPPER(SUBSTRING(@string, @Index, 1))
        END
    ELSE
        BEGIN

            SET @ResultString = @ResultString + LOWER(SUBSTRING(@string, @Index, 1)) 
        END 

    SET @Index = @Index+ 1--increase the index
END
SELECT @ResultString

结尾

于 2017-12-11T13:59:30.730 回答
0

仅限英文数据。

从性能的角度来看超级非高效,但从生产力的角度来看是高效的。将其用作一次性转换器:

SELECT 
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(

UPPER(LEFT(City,1))+LOWER(SUBSTRING(City,2,LEN(City)))

,' 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')


FROM [Dictionaries].[dbo].[Cities]
  WHERE Country = 'US' AND City like '% %'
  ORDER BY City
于 2018-06-25T21:26:17.237 回答
0

我正在寻找最好的大写方式,我重新创建了简单的 sql 脚本

如何使用 SELECT dbo.Capitalyze('这是一个有多个空格的测试')

结果“这是一个包含多个空格的测试”

CREATE FUNCTION Capitalyze(@input varchar(100) ) 返回 varchar(100) 作为开始

declare @index int=0
declare @char as varchar(1)=' '
declare @prevCharIsSpace as bit=1
declare @Result as varchar(100)=''

set @input=UPPER(LEFT(@input,1))+LOWER(SUBSTRING(@input, 2, LEN(@input)))
set @index=PATINDEX('% _%',@input)
if @index=0
    set @index=len(@input)
set @Result=substring(@input,0,@index+1)

WHILE (@index < len(@input))
BEGIN
    SET @index = @index + 1
    SET @char=substring(@input,@index,1)
    if (@prevCharIsSpace=1)
    begin
        set @char=UPPER(@char)
        if (@char=' ')
            set @char=''
    end

    if (@char=' ')
        set @prevCharIsSpace=1
    else
        set @prevCharIsSpace=0

    set @Result=@Result+@char
    --print @Result
END
--print @Result
return @Result

结尾

于 2018-09-12T01:22:43.223 回答
0

fname 是列名,如果 fname 值为 akhil,则 UPPER(left(fname,1)) 提供大写首字母 (A) 和子字符串函数 SUBSTRING(fname,2,LEN(fname)) 提供(khil) 使用 + 然后结果连接两者是(阿基尔)

select UPPER(left(fname,1))+SUBSTRING(fname,2,LEN(fname)) as fname
FROM [dbo].[akhil]
于 2018-10-03T06:59:49.780 回答
0

SQL Server 2016+ 上使用 JSON 提供保证的单词顺序:

CREATE FUNCTION [dbo].[InitCap](@Text NVARCHAR(MAX))
RETURNS NVARCHAR(MAX)
AS
BEGIN
    RETURN STUFF((
        SELECT ' ' + UPPER(LEFT(s.value,1)) + LOWER(SUBSTRING(s.value,2,LEN(s.value)))
        FROM OPENJSON('["' + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@Text,'\','\\'),'"','\"'),CHAR(9),'\t'),CHAR(10),'\n'),' ','","') + '"]') s
        ORDER BY s.[key]
    FOR XML PATH(''),TYPE).value('(./text())[1]','NVARCHAR(MAX)'),1,1,'');
END
于 2019-10-09T02:10:56.143 回答
0
GO
CREATE FUNCTION [dbo].[Capitalize](@text NVARCHAR(MAX)) RETURNS NVARCHAR(MAX) AS
BEGIN
    DECLARE @result NVARCHAR(MAX) = '';
    DECLARE @c NVARCHAR(1);
    DECLARE @i INT = 1;
    DECLARE @isPrevSpace BIT = 1;

    WHILE @i <= LEN(@text)
    BEGIN
        SET @c = SUBSTRING(@text, @i, 1);
        SET @result += IIF(@isPrevSpace = 1, UPPER(@c), LOWER(@c));
        SET @isPrevSpace = IIF(@c LIKE '[    -]', 1, 0);
        SET @i += 1;
    END
    RETURN @result;
END
GO

DECLARE @sentence NVARCHAR(100) = N'i-thINK-this    soLUTION-works-LiKe-a charm';
PRINT dbo.Capitalize(@sentence);
-- I-Think-This Solution-Works-Like-A Charm
于 2020-11-20T07:06:52.000 回答
0

SELECT dbo.ProperCase('Xyz 在 qrst 之后')

于 2021-03-04T14:58:51.507 回答
0

它可以像这样简单:

DECLARE @Name VARCHAR(10) = 'merin';

SELECT @Name AS Name, REPLACE(@Name, LEFT(@Name, 1),  UPPER(LEFT(@Name, 1))) AS CapitalizedName

在此处输入图像描述

于 2021-06-02T18:56:22.540 回答
0

建议的功能可以正常工作,但是,如果您不想创建任何功能,我就是这样做的-

select ID,Name
,string_agg(concat(upper(substring(value,1,1)),lower(substring(value,2,len(value)-1))),' ') as ModifiedName 
from Table_Customer 
cross apply String_Split(replace(trim(Name),'  ',' '),' ')
where Name is not null
group by ID,Name;

上面的查询用空格 (' ') 分割单词并创建每个具有一个子字符串的不同行,然后将每个子字符串的第一个字母转换为大写字母并保持保持为小写字母。最后一步是根据键进行字符串聚合。

希望你觉得它有用!

于 2021-06-16T08:00:18.237 回答
-1
IF OBJECT_ID ('dbo.fnCapitalizeFirstLetterAndChangeDelimiter') IS NOT NULL
    DROP FUNCTION dbo.fnCapitalizeFirstLetterAndChangeDelimiter
GO

CREATE FUNCTION [dbo].[fnCapitalizeFirstLetterAndChangeDelimiter] (@string NVARCHAR(MAX), @delimiter NCHAR(1), @new_delimeter NCHAR(1))
RETURNS NVARCHAR(MAX)
AS 
BEGIN
    DECLARE @result NVARCHAR(MAX)
    SELECT @result = '';
    IF (LEN(@string) > 0)
        DECLARE @curr INT
        DECLARE @next INT
        BEGIN
            SELECT @curr = 1
            SELECT @next = CHARINDEX(@delimiter, @string)
            WHILE (LEN(@string) > 0)
                BEGIN
                    SELECT @result = 
                        @result + 
                        CASE WHEN LEN(@result) > 0 THEN @new_delimeter ELSE '' END +
                        UPPER(SUBSTRING(@string, @curr, 1)) + 
                        CASE 
                            WHEN @next <> 0 
                            THEN LOWER(SUBSTRING(@string, @curr+1, @next-2))
                            ELSE LOWER(SUBSTRING(@string, @curr+1, LEN(@string)-@curr))
                        END
                    IF (@next > 0)
                        BEGIN
                            SELECT @string = SUBSTRING(@string, @next+1, LEN(@string)-@next)
                            SELECT @next = CHARINDEX(@delimiter, @string)
                        END
                    ELSE
                        SELECT @string = ''
                END
        END
    RETURN @result
END
GO
于 2019-06-06T16:22:37.353 回答
-3

你应该试试这个

Select INITCAP(column_name) from table_name;

这将大写提到的属性条目的第一个字母。

于 2016-09-13T18:00:12.583 回答