有谁知道如何从字符串中以大写字母开头分割单词?
示例:
DECLARE @var1 varchar(100) = 'OneTwoThreeFour'
DECLARE @var2 varchar(100) = 'OneTwoThreeFourFive'
DECLARE @var3 varchar(100) = 'One'
SELECT @var1 as Col1, <?> as Col2
SELECT @var2 as Col1, <?> as Col2
SELECT @var3 as Col1, <?> as Col2
预期结果:
Col1 Col2
OneTwoThreeFour One Two three Four
OneTwoThreeFourFive One Two Three Four Five
One One
如果这不可能(或者如果太长),标量函数也可以。
答案 0 :(得分:17)
这是我创建的一个类似于&#34;删除非字母字符&#34;的函数。 How to strip all non-alphabetic characters from string in SQL Server?
这个使用区分大小写的排序规则,它主动寻找非空格/大写字母组合,然后使用STUFF函数插入空格。这是一个标量UDF,因此有些人会立即说它会比其他解决方案慢。对于这个概念,我说,请测试一下。此函数不使用任何表数据,只根据需要循环多次,因此它可能会给您带来非常好的性能。
Create Function dbo.Split_On_Upper_Case(@Temp VarChar(1000))
Returns VarChar(1000)
AS
Begin
Declare @KeepValues as varchar(50)
Set @KeepValues = '%[^ ][A-Z]%'
While PatIndex(@KeepValues collate Latin1_General_Bin, @Temp) > 0
Set @Temp = Stuff(@Temp, PatIndex(@KeepValues collate Latin1_General_Bin, @Temp) + 1, 0, ' ')
Return @Temp
End
这样称呼:
Select dbo.Split_On_Upper_Case('OneTwoThreeFour')
Select dbo.Split_On_Upper_Case('OneTwoThreeFour')
Select dbo.Split_On_Upper_Case('One')
Select dbo.Split_On_Upper_Case('OneTwoThree')
Select dbo.Split_On_Upper_Case('stackOverFlow')
Select dbo.Split_On_Upper_Case('StackOverFlow')
答案 1 :(得分:3)
这是我刚刚创建的一个函数。
<强>功能强>
CREATE FUNCTION dbo.Split_On_Upper_Case
(
@String VARCHAR(4000)
)
RETURNS VARCHAR(4000)
AS
BEGIN
DECLARE @Char CHAR(1);
DECLARE @i INT = 0;
DECLARE @OutString VARCHAR(4000) = '';
WHILE (@i <= LEN(@String))
BEGIN
SELECT @Char = SUBSTRING(@String, @i,1)
IF (@Char = UPPER(@Char) Collate Latin1_General_CS_AI)
SET @OutString = @OutString + ' ' + @Char;
ELSE
SET @OutString = @OutString + @Char;
SET @i += 1;
END
SET @OutString = LTRIM(@OutString);
RETURN @OutString;
END
测试数据
DECLARE @TABLE TABLE (Strings VARCHAR(1000))
INSERT INTO @TABLE
VALUES ('OneTwoThree') ,
('FourFiveSix') ,
('SevenEightNine')
<强>查询强>
SELECT dbo.Split_On_Upper_Case(Strings) AS Vals
FROM @TABLE
结果集
╔══════════════════╗
║ Vals ║
╠══════════════════╣
║ One Two Three ║
║ Four Five Six ║
║ Seven Eight Nine ║
╚══════════════════╝
答案 2 :(得分:2)
如果需要单个查询,则可以使用REPLACE检查每个大写字母,如
SELECT @var1 col1, REPLACE(
REPLACE(
REPLACE(
...
REPLACE(@var1, 'A', ' A')
, ...
, 'X', ' X')
, 'Y', ' Y')
, 'Z', ' Z') col2
不是最美丽的东西,但它会起作用。
修改强>
只是添加另一个函数以与其他答案不同的方式做同样的事情
CREATE FUNCTION splitCapital (@param Varchar(MAX))
RETURNS Varchar(MAX)
BEGIN
Declare @ret Varchar(MAX) = '';
declare @len int = len(@param);
WITH Base10(N) AS (
SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7
UNION ALL SELECT 8 UNION ALL SELECT 9
), Chars(N) As (
Select TOP(@len)
nthChar
= substring(@param, u.N + t.N*10 + h.N*100 + th.N*1000 + 1, 1)
Collate Latin1_General_CS_AI
FROM Base10 u
CROSS JOIN Base10 t
CROSS JOIN Base10 h
CROSS JOIN Base10 th
WHERE u.N + t.N*10 + h.N*100 + th.N*1000 < @len
ORDER BY u.N + t.N*10 + h.N*100 + th.N*1000
)
SELECT @ret += Case nthChar
When UPPER(nthChar) Then ' '
Else ''
End + nthChar
FROM Chars
RETURN @ret;
END
这个使用TSQL连接字符串变量的可能性,我不得不使用TOP N技巧以正确的顺序强制Chars CTE行
答案 3 :(得分:1)
构建Numbers表。 SO上有一些优秀的帖子向您展示如何做到这一点。使用高于输入字符串最大长度的值填充它。选择从1到当前输入字符串的实际长度的值。将此数字列表交叉连接到输入字符串。将结果用于SUBSTRING()
每个字符。然后你可以 将得到的one-charachter值列表与预先填充的表值变量或进行比较,使用ASCII()
将每个字符转换为整数只选择介于65('A')和90('Z')之间的那些。此时,您有一个列表,它是输入字符串中每个大写字符的位置。 UNION
输入字符串到此列表末尾的最大长度。你会在一瞬间看到原因。现在你可以SUBSTRING()
输入变量,从行N给出的数字开始,取一个长度(由行N + 1给出的数字) - (行N给出的数字)。这就是为什么你必须UNION
最后的额外数字。最后,使用您选择的算法将所有这些子串连接在一起,以空格分隔。
抱歉,我面前没有实例可以试用代码。听起来很有趣。我认为使用嵌套的SELECT
语句进行此操作会变得错综复杂且无法维护;更好地将其列为CTE,恕我直言。
答案 4 :(得分:0)
我使用的是ITVF功能(表格功能)。 在性能方面,内联函数的工作方式类似于视图
CREATE FUNCTION [dbo].[udf_Split_Capitals_In_Str]
(@str VARCHAR(8000))
RETURNS TABLE AS RETURN
WITH Tally (n) AS
(
SELECT TOP (LEN (@str)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM (VALUES (0),(0),(0),(0),(0),(0),(0),(0)) a(n)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) b(n)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) c(n)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) d(n)
)
SELECT New_Str = STUFF((
SELECT
CASE
WHEN SUBSTRING(@str, n,1) = UPPER(SUBSTRING(@str, n,1)) Collate Latin1_General_CS_AI AND n > 1
THEN ' ' + SUBSTRING(@str, n,1)
ELSE SUBSTRING(@str, n,1)
END
FROM Tally
FOR XML PATH ('')),1,0,'')
/*How To use:*/
SELECT * FROM dbo.udf_Split_Capitals_In_Str ('HelloWorld')
/*Cross Apply Example*/
SELECT T.* , Fixed_Name.New_Str FixedName
FROM
(
SELECT Id= 1 , Name = 'DonaldTrump'
UNION ALL
SELECT Id= 2 , Name = 'HilaryClinton'
) T
CROSS APPLY dbo.udf_Split_Capitals_In_Str (T.Name) Fixed_Name
答案 5 :(得分:0)
我知道那里已经有了一些很好的答案,但是如果你想避免创建一个函数,你也可以使用递归CTE来完成这个。这当然不是一种干净的方式,但它确实有效。
DECLARE
@camelcase nvarchar(4000) = 'ThisIsCamelCased'
;
WITH
split
AS
(
SELECT
[iteration] = 0
,[string] = @camelcase
UNION ALL
SELECT
[iteration] = split.[iteration] + 1
,[string] = STUFF(split.[string], pattern.[index] + 1, 0, ' ')
FROM
split
CROSS APPLY
( SELECT [index] = PATINDEX(N'%[^ ][A-Z]%' COLLATE Latin1_General_Bin, split.[string]) )
pattern
WHERE
pattern.[index] > 0
)
SELECT TOP (1)
[spaced] = split.[string]
FROM
split
ORDER BY
split.[iteration] DESC
;
正如我所说,这不是一种编写查询的好方法,但是当我只是编写一些我不希望在数据库中添加新工件的临时查询时,我会使用这样的东西。您也可以使用它来创建函数作为内联表值函数,这总是更好。
答案 6 :(得分:0)
请尝试以下操作:
declare @t nvarchar (100) ='IamTheTestString'
declare @len int
declare @Counter int =0
declare @Final nvarchar (100) =''
set @len =len( @t)
while (@Counter <= @len)
begin
set @Final= @Final + Case when ascii(substring (@t,@Counter,1))>=65 and
ascii(substring (@t,@Counter,1))<=90 then ' '+substring (@t,@Counter,1) else
substring (@t,@Counter,1) end
set @Counter=@Counter+1
end
print ltrim(@Final)