【发布时间】:2017-05-24 19:43:51
【问题描述】:
我有一列包含混合大小写字符的字符串值,例如 (AliBabaSaidHello)。我想将此列值用于我的 SSRS 表格单元格标题,例如(阿里巴巴说你好)。首先,我喜欢找到每个大写字母并为其添加空格。
【问题讨论】:
标签: sql-server tsql reporting-services replace
我有一列包含混合大小写字符的字符串值,例如 (AliBabaSaidHello)。我想将此列值用于我的 SSRS 表格单元格标题,例如(阿里巴巴说你好)。首先,我喜欢找到每个大写字母并为其添加空格。
【问题讨论】:
标签: sql-server tsql reporting-services replace
Ascii 65-90 提示有助于为函数创建以下代码:
declare @Reset bit;
declare @Ret varchar(8000);
declare @i int;
declare @c char(1);
select @Reset = 1, @i=1, @Ret = '';
while (@i <= len('AliBabaSaidHello'))
select @c= substring('AliBabaSaidHello',@i,1),
@Reset = case when ascii(@c) between 65 and 90 then 1 else 0 end,
@Ret = @Ret + case when @Reset=1 then ' ' + @c else @c end,
@i = @i +1
select @Ret
谢谢大家,在阅读了所有答案后,我创建了这个灵活且非常高效的功能:
FUNCTION dbo.UDF_DelimitersForCases (@string NVARCHAR(MAX), @Delimiter char(1))
RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE @len INT = LEN(@string)
,@iterator INT = 2 --Don't put space to left of first even if it's a capital
;
WHILE @iterator <= LEN(@string)
BEGIN
IF PATINDEX('[ABCDEFGHIJKLMNOPQRSTUVWXYZ]',SUBSTRING(@string,@iterator,1) COLLATE Latin1_General_CS_AI) <> 0
BEGIN
SET @string = STUFF(@string,@iterator,0,@Delimiter);
SET @iterator += 1;
END
;
SET @iterator += 1;
END
RETURN @string;
END
;
GO
示例:
SELECT dbo.udf_DelimitersForCases('AliBabaSaidHello','_');
返回 "Ali_Baba_Said_Hello"(无引号)。
【讨论】:
逐一获取“A”、“l”、“i”等字符,查看方法ascii('&i_char')的返回值是否在65和90之间,这些是“大写字母”。
(ascii('A')=65(capital), ascii('l')=108(non-capital), ascii('i')=105(non-capital))
【讨论】:
为您的 qry 使用 case sensitive 排序规则,并与 每个字符 结合使用。当您迭代字符时,您可以轻松地将大写字符替换为大写字符 + 空格。
WHERE SourceText COLLATE Latin1_General_CS_AI like '[A-Z]'
-- or for variable @char COLLATE Latin1_General_CS_AI = upper(@char)
Latin1_General_CS_AI 中的重要,其中“CS”区分大小写。
【讨论】:
如果您出于某种原因想要使其可重用,这里是使用户函数调用的代码。
DROP FUNCTION IF EXISTS udf_SpacesforCases;
GO
CREATE FUNCTION udf_SpacesForCases (@string NVARCHAR(MAX))
RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE @len INT = LEN(@string)
,@iterator INT = 2 --Don't put space to left of first even if it's a capital
;
WHILE @iterator <= LEN(@string)
BEGIN
IF PATINDEX('[ABCDEFGHIJKLMNOPQRSTUVWXYZ]',SUBSTRING(@string,@iterator,1) COLLATE Latin1_General_CS_AI) <> 0
BEGIN
SET @string = STUFF(@string,@iterator,0,' ');
SET @iterator += 1;
END
;
SET @iterator += 1;
END
RETURN @string;
END
;
GO
SELECT dbo.udf_SpacesForCases('AliBabaSaidHello');
【讨论】:
任何涉及标量用户定义函数和/或循环的解决方案都不会像基于集合的解决方案那样执行。这是一个使用NGrams8K 的小菜一碟:
DECLARE @string varchar(1000) = 'AliBabaSaidHello';
SELECT newString =
( SELECT
CASE
WHEN ASCII(token) BETWEEN 65 AND 90 AND position > 1 THEN ' '+token ELSE token
END+''
FROM dbo.NGrams8k(@string, 1)
FOR XML PATH(''));
返回:“阿里巴巴说你好”(无引号)。
请注意,第一个字符之前没有空格。或者,不使用该函数的基于集合的解决方案如下所示:
WITH
E1(N) AS (SELECT 1 FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(c)),
iTally(N) AS
(
SELECT TOP (LEN(@string)) ROW_NUMBER() OVER (ORDER BY (SELECT 1))
FROM E1 a, E1 b, E1 c, E1 d
),
nGrams(NewString) AS
(
SELECT
CASE WHEN ASCII(SUBSTRING(@string, N, 1)) BETWEEN 65 AND 90 AND N > 1
THEN ' '+SUBSTRING(@string, N, 1) ELSE SUBSTRING(@string, N, 1)
END+''
FROM iTally
FOR XML PATH('')
)
SELECT NewString
FROM nGrams;
【讨论】:
APL 方法是将输入拆分为字符,根据需要填充字符,然后重新组合字符串。在 T-SQL 中,它看起来更像这样:
-- Sample data.
declare @Samples as Table ( Sample VarChar(32) );
insert into @Samples ( Sample ) values ( 'AliBabaSaidHello' ), ( 'MeshMuscleShirt' );
select * from @Samples;
-- Stuff it.
with
Ten ( Number ) as ( select Number from ( values (0), (1), (2), (3), (4), (5), (6), (7), (8), (9) ) as Digits( Number ) ),
TenUp2 ( Number ) as ( select 42 from Ten as L cross join Ten as R ),
TenUp4 ( Number ) as ( select 42 from TenUp2 as L cross join TenUp2 as R ),
Numbers ( Number ) as ( select Row_Number() over ( order by ( select NULL ) ) from TenUp4 ),
Characters ( Sample, Number, PaddedCh ) as (
select S.Sample, N.Number, PC.PaddedCh
from @Samples as S inner join
Numbers as N on N.Number <= Len( S.Sample ) cross apply
( select SubString( S.Sample, N.Number, 1 ) as Ch ) as SS cross apply
( select case when N.Number > 1 and ASCII( 'A' ) <= ASCII( SS.Ch ) and ASCII( SS.Ch ) <= ASCII( 'Z' ) then ' ' + Ch else Ch end as PaddedCh ) as PC )
select S.Sample,
( select PaddedCh from Characters where Sample = S.Sample order by Number for XML path(''), type).value('.[1]', 'VarChar(max)' ) as PaddedSample
from @Samples as S
order by Sample;
【讨论】:
42,它是我选择的占位符(即使它不是答案)表明我考虑过需要什么答案是语法上令人满意且语义上不重要的东西。现在快速说 10 次“网状肌肉衬衫”。
另一个选项(相当冗长)可能是:
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('AliBabaSaidHello' COLLATE Latin1_General_CS_AS,'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')
【讨论】: