【问题标题】:What’s the best way to capitalise the first letter of each word in a string in SQL Server在 SQL Server 中将字符串中每个单词的首字母大写的最佳方法是什么
【发布时间】:2010-09-08 11:26:23
【问题描述】:

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

【问题讨论】:

  • 这必须在 SQL Server 中完成吗?我不会将它与数据库服务器相关联,而是通过表单验证甚至视图来完成。
  • PostgreSQL 用户:UPDATE [table] SET your_col = initcap(lower(your_col));这不是 Postgre 问题,但无论如何它都会首先出现在 google 中。

标签: sql sql-server string


【解决方案1】:

来自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

【讨论】:

  • UPPER(@Char) != 'S' 是什么意思?我们为什么要使用它?
  • 与'S'的比较是为了确保在写that's这样的单词时S不大写
  • 功能有点慢,但工作正常。如何提高性能?
  • 不适用于具有' 且后面没有S 的单词。如I'myou've
  • 为什么当输入为 4000 时 OutputString 为 255 并且也返回?
【解决方案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

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

【讨论】:

    【解决方案3】:

    另一种不使用循环的解决方案 - 具有递归 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
    

    【讨论】:

      【解决方案4】:

      这是最简单的一行代码。

      select 
              LEFT(column, 1)+ lower(RIGHT(column, len(column)-1) )
           from [tablename]
      

      【讨论】:

      • 注意,每一列都应该去掉空格,否则会中断。
      • 另外,你没有在第一个字母上做大写。
      • 这仅将列的第一个字母大写
      • @Amrik 正如@JohnnyBizzle 上面评论的那样,我认为您的意思是:select UPPER(LEFT(column, 1)) + lower(RIGHT(column, len(column)-1) ) from [tablename]
      • 使用lower (stuff (column, 1,1, '')) 而不是lower(RIGHT(column, len(column)-1) )
      【解决方案5】:

      你应该试试这个

      Select INITCAP(column_name) from table_name;
      

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

      【讨论】:

      • "INITCAP" 不是内置函数 - 您需要提供函数定义。
      • 我在 Oracle MYSQL 中使用 INITCAP,它工作得非常好
      • 是的,但问题具体说明了 SQL Server。
      【解决方案6】:

      作为表值函数:

      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_LEVEL 130。

      【讨论】:

      • 请注意STRING_SPLIT函数的非保证顺序。我会在 FROM 行之后添加 ORDER BY CHARINDEX(value,@v)
      【解决方案7】:
      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
      

      结束

      【讨论】:

      • 在 SQL Server 中将第一个字符大写的非常简单的方法
      【解决方案8】:

      仅适用于英文数据。

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

      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
      

      【讨论】:

        【解决方案9】:

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

        如何使用SELECT dbo.Capitalyze('this is a test with multiple spaces')

        result "这是一个有多个空格的测试"

        创建函数 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
        

        结束

        【讨论】:

          【解决方案10】:

          如果 fname 值为 akhil 则 UPPER(left(fname,1)) 为列名+ 然后结果是 (Akhil)

          select UPPER(left(fname,1))+SUBSTRING(fname,2,LEN(fname)) as fname
          FROM [dbo].[akhil]
          

          【讨论】:

          • 给出一些解释,以便于理解解决方案
          • 嗨@Harsha B,如果有任何查询评论,我会解释它。
          【解决方案11】:

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

          SQL> select INITCAP(dname) from department;
          
          INITCAP(DNAME)
          --------------------------------------------------
          Sales
          Management
          Production
          Development
          

          【讨论】:

            【解决方案12】:
            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
            

            【讨论】:

            【解决方案13】:

            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
            

            【讨论】:

              【解决方案14】:
              ;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).

              【讨论】:

                【解决方案15】:
                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
                

                【讨论】:

                  【解决方案16】:

                  SELECT dbo.ProperCase('Xyz is AFTER qrst')

                  【讨论】:

                  • dbo.ProperCase 不是原生函数...
                  【解决方案17】:

                  可以这么简单:

                  DECLARE @Name VARCHAR(10) = 'merin';
                  
                  SELECT @Name AS Name, REPLACE(@Name, LEFT(@Name, 1),  UPPER(LEFT(@Name, 1))) AS CapitalizedName
                  

                  【讨论】:

                  • 啊这将整个字符串中的第一个字母大写。所以“罗杰”变成了“罗杰”。
                  【解决方案18】:

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

                  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;
                  

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

                  希望你觉得它有用!

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2014-06-19
                    • 2011-01-20
                    • 2012-07-24
                    • 2014-05-19
                    • 2021-09-07
                    • 2010-12-05
                    相关资源
                    最近更新 更多