简体   繁体   English

SQL服务器中字符串中每个单词的首字母如何大写

[英]How to capitalize the first letter of each word in a string in SQL Server

What's the best way to capitalize the first letter of each word in a string in SQL Server.在 SQL 服务器中,将字符串中每个单词的首字母大写的最佳方法是什么。

From http://www.sql-server-helper.com/functions/initcap.aspx来自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

There is a simpler/smaller one here (but doesn't work if any row doesn't have spaces, "Invalid length parameter passed to the RIGHT function."):这里有一个更简单/更小的一个(但如果任何行没有空格,“无效的长度参数传递给 RIGHT 函数。”):

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

As a table-valued function:作为表值函数:

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

Note that string_split requires COMPATIBILITY_LEVEL 130.请注意, string_split需要COMPATIBILITY_LEVEL 130。

Another solution without using the loop - pure set-based approach with recursive CTE不使用循环的另一种解决方案 - 具有递归 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

If you are looking for the answer to the same question in Oracle/PLSQL then you may use the function INITCAP.如果您正在 Oracle/PLSQL 中寻找相同问题的答案,那么您可以使用函数 INITCAP。 Below is an example for the attribute dname from a table department which has the values ('sales', 'management', 'production', 'development').下面是一个来自表部门的属性dname的示例,它具有值('sales'、'management'、'production'、'development')。

SQL> select INITCAP(dname) from department;

INITCAP(DNAME)
--------------------------------------------------
Sales
Management
Production
Development

A variation of the one I've been using for quite some time is:我已经使用了很长时间的一个变体是:

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

You can easily modify to handle characters after items other than spaces if you wanted to.如果您愿意,您可以轻松修改以处理除空格以外的项目之后的字符。

这是执行此操作的最简单的单行代码:

SELECT LEFT(column, 1)+ lower(RIGHT(column, len(column)-1) ) FROM [tablename]
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
END

fname is column name if fname value is akhil then UPPER(left(fname,1)) provide capital First letter(A) and substring function SUBSTRING(fname,2,LEN(fname)) provide(khil) concate both using + then result is (Akhil)如果 fname 值为 akhil,则 fname 为列名是(阿基尔)

select UPPER(left(fname,1))+SUBSTRING(fname,2,LEN(fname)) as fname
FROM [dbo].[akhil]
;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 

This will result in:这将导致:

  • Andrew-Le-Smith安德鲁-勒-史密斯
  • Bobs-Your-Uncle Bobs-Your-Uncle
  • Carl-Van卡尔-范
  • Dean O'Brian迪恩·奥布莱恩
  • Eddy Thompson艾迪汤普森

Using a recursive CTE set based query should out perform a procedural while loop query.使用基于递归 CTE 集的查询应该胜过执行过程式 while 循环查询。 Here I also have made my separate to be 3 different characters [-' ] instead of 1 for a more advanced example.在这里,对于更高级的示例,我还将我的单独设置为 3 个不同的字符 [-' ] 而不是 1。 Using PATINDEX as I have done allows me to look for many characters.像我所做的那样使用 PATINDEX 可以让我查找许多字符。 You could also use CHARINDEX on a single character and this function excepts a third parameter StartFromPosition so I could further simply my 2nd part of the recursion of the pos formula to (assuming a space): pos = CHARINDEX(' ', Name, pos + 1).您也可以在单个字符上使用 CHARINDEX,并且此函数除了第三个参数 StartFromPosition,因此我可以进一步简单地将 pos 公式的第二部分递归到(假设一个空格): pos = CHARINDEX(' ', Name, pos + 1)。

It can be as simple as this:它可以像这样简单:

DECLARE @Name VARCHAR(500) = 'Roger';

SELECT @Name AS Name, UPPER(LEFT(@Name, 1)) + SUBSTRING(@Name, 2, LEN(@Name)) AS CapitalizedName;

在此处输入图像描述

I was looking for the best way to capitalize and i recreate simple sql script我正在寻找最好的大写方式,我重新创建了简单的 sql 脚本

how to use SELECT dbo.Capitalyze('this is a test with multiple spaces')如何使用 SELECT dbo.Capitalyze('这是一个有多个空格的测试')

result "This Is A Test With Multiple Spaces"结果“这是一个包含多个空格的测试”

CREATE FUNCTION Capitalyze(@input varchar(100) )
    returns varchar(100)
as
begin
    
    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
end

On SQL Server 2016+ using JSON which gives guaranteed order of the words: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
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

The suggested function works fine, however, if you do not want to create any function this is how I do it:建议的功能可以正常工作,但是,如果您不想创建任何功能,我就是这样做的:

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;

The above query split the words by space (' ') and create different rows of each having one substring, then convert the first letter of each substring to upper and keep remaining as lower.上面的查询用空格 (' ') 分割单词并创建不同的行,每个行都有一个子字符串,然后将每个子字符串的第一个字母转换为大写字母并保持为小写字母。 The final step is to string aggregate based on the key.最后一步是根据键进行字符串聚合。

update TableName set
 Title = LOWER(LEFT(ColumnName,1))+ RIGHT(ColumnName,LEN(Title)-1)
 where ...

We can use TRIM and more optimization depends on the case.我们可以使用TRIM,更多的优化取决于具体情况。 BUT this is a fire-fighting stage, NOT to be solved by creating a DB function!!但这是一个救火阶段,不能通过创建数据库函数来解决!! Update statement should only be used once as the last option!.更新语句只能作为最后一个选项使用一次!。 In Real-Life, we fix existing records [using a similar update statement], then test the impact through a painful process.在现实生活中,我们[使用类似的更新语句]修复现有记录,然后通过痛苦的过程测试影响。 However, the solution starts only after by trying to handle or govern the data entry as a root Couse [mostly with similar mechanism, ultimately, we can avoid it from Highest layer [The Interface] by implementing a role to convert before saving, or to prevent the insertion with warning, but absolutely not through DB function!.但是,该解决方案仅在尝试以根 Couse 处理或管理数据输入之后才开始[主要使用类似的机制,最终,我们可以通过在保存之前实现一个角色转换来避免它从最高层 [接口],或者用警告防止插入,但绝对不能通过 DB 函数!

For English only data.仅限英文数据。

Super non-efficient from view of performance but efficient from view of productivity.从性能的角度来看超级非高效,但从生产力的角度来看是高效的。 Use it as one-time converter:将其用作一次性转换器:

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

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

You should try this instead你应该试试这个

Select INITCAP(column_name) from table_name;

This will Capitalize the first letter of mentioned attributes entries.这将大写提到的属性条目的第一个字母。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM