[英]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:这将导致:
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)。
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.