Sql server 优化查找字符串中第n次出现的字符
我编写了一个sql server函数,它在第n个字符出现之前返回子字符串 比如说,,Sql server 优化查找字符串中第n次出现的字符,sql-server,Sql Server,我编写了一个sql server函数,它在第n个字符出现之前返回子字符串 比如说,, 选择dbo.fn\u getfirstnthstation('.',hello world.It.is.raining.today',3) 结果返回“helloworld.It.Is.” 我写的函数看起来又脏又慢,所以我想对它进行优化。 如有任何建议,请保持清洁,不胜感激 多谢各位 CREATE FUNCTION fn_getFirstNthSentence ( @TargetStr VARCHAR(MAX
选择dbo.fn\u getfirstnthstation('.',hello world.It.is.raining.today',3)
结果返回“helloworld.It.Is.”
我写的函数看起来又脏又慢,所以我想对它进行优化。
如有任何建议,请保持清洁,不胜感激
多谢各位
CREATE FUNCTION fn_getFirstNthSentence
(
@TargetStr VARCHAR(MAX) ,
@SearchedStr VARCHAR(8000) ,
@Occurrence INT
)
RETURNS varchar(MAX)
AS
BEGIN
DECLARE @pos INT ,
@counter INT ,
@ret INT;
SET @pos = CHARINDEX(@TargetStr, @SearchedStr);
IF ( @pos = 0 )
RETURN @SearchedStr
SET @counter = 1;
IF @Occurrence = 1
SET @ret = @pos;
ELSE
BEGIN
WHILE ( @counter < @Occurrence )
BEGIN
IF(LEN(@SearchedStr) < @pos + 1)
RETURN @SearchedStr
SELECT @ret = CHARINDEX(@TargetStr, @SearchedStr,
@pos + 1);
IF(@ret = 0)
RETURN @SearchedStr
SET @counter = @counter + 1;
SET @pos = @ret;
END;
END;
RETURN LEFT(@SearchedStr, @ret)
END;
创建函数fn\u getfirstnthstation
(
@TargetStr VARCHAR(最大值),
@SearchedStr VARCHAR(8000),
@发生整数
)
返回varchar(最大值)
作为
开始
声明@pos INT,
@计数器INT,
@ret INT;
设置@pos=CHARINDEX(@TargetStr,@SearchedStr);
如果(@pos=0)
返回@SearchedStr
设置@counter=1;
如果@Occurrence=1
设置@ret=@pos;
其他的
开始
WHILE(@计数器<@事件)
开始
如果(LEN(@SearchedStr)<@pos+1)
返回@SearchedStr
选择@ret=CHARINDEX(@TargetStr、@SearchedStr、,
@pos+1);
如果(@ret=0)
返回@SearchedStr
设置@counter=@counter+1;
设置@pos=@ret;
结束;
结束;
返回左侧(@SearchedStr,@ret)
结束;
——我发现这些函数是一个雷区,冒着踩到地雷的风险,我尝试了一些简化——也许是性能的微观改进
alter FUNCTION fn_getFirstNthSentence
(
@TargetStr VARCHAR(MAX) ,
@SearchedStr VARCHAR(8000) ,
@Occurrence INT
)
RETURNS varchar(MAX)
AS
BEGIN
DECLARE @pos INT ,
@counter INT ;
IF @Occurrence < 1
RETURN NULL;
SELECT @counter = 0, @POS = 1;
WHILE (@counter < @Occurrence AND @POS > 0)
BEGIN
SELECT @POS = CHARINDEX(@TargetStr, @SearchedStr,
@pos + 1);
IF @POS > 0
SET @counter = @counter + 1;
END;
RETURN CASE WHEN @POS > 0 THEN
LEFT(@SearchedStr, @POS)
ELSE
@SearchedStr
END;
END;
alter函数fn\u getfirstnthstation
(
@TargetStr VARCHAR(最大值),
@SearchedStr VARCHAR(8000),
@发生整数
)
返回varchar(最大值)
作为
开始
声明@pos INT,
@计数器INT;
如果@Occurrence<1
返回NULL;
选择@counter=0、@POS=1;
而(@counter<@事件和@POS>0)
开始
选择@POS=CHARINDEX(@TargetStr、@SearchedStr、,
@pos+1);
如果@POS>0
设置@counter=@counter+1;
结束;
当@POS>0时返回案例,然后
左(@SearchedStr,@POS)
其他的
@搜索STR
结束;
结束;
——我发现这些函数是一个雷区,冒着踩到地雷的风险,我尝试了一些简化——也许是性能的微观改进
alter FUNCTION fn_getFirstNthSentence
(
@TargetStr VARCHAR(MAX) ,
@SearchedStr VARCHAR(8000) ,
@Occurrence INT
)
RETURNS varchar(MAX)
AS
BEGIN
DECLARE @pos INT ,
@counter INT ;
IF @Occurrence < 1
RETURN NULL;
SELECT @counter = 0, @POS = 1;
WHILE (@counter < @Occurrence AND @POS > 0)
BEGIN
SELECT @POS = CHARINDEX(@TargetStr, @SearchedStr,
@pos + 1);
IF @POS > 0
SET @counter = @counter + 1;
END;
RETURN CASE WHEN @POS > 0 THEN
LEFT(@SearchedStr, @POS)
ELSE
@SearchedStr
END;
END;
alter函数fn\u getfirstnthstation
(
@TargetStr VARCHAR(最大值),
@SearchedStr VARCHAR(8000),
@发生整数
)
返回varchar(最大值)
作为
开始
声明@pos INT,
@计数器INT;
如果@Occurrence<1
返回NULL;
选择@counter=0、@POS=1;
而(@counter<@事件和@POS>0)
开始
选择@POS=CHARINDEX(@TargetStr、@SearchedStr、,
@pos+1);
如果@POS>0
设置@counter=@counter+1;
结束;
当@POS>0时返回案例,然后
左(@SearchedStr,@POS)
其他的
@搜索STR
结束;
结束;
另一个选项是通过XML
我看不到您的基准测试,但它肯定是远远少于代码。添加的选项可以通过添加一个参数并更改,其中Seq另一个选项是通过XML来查找第3到第5个匹配项
我看不到您的基准测试,但它肯定是远远少于代码。添加的选项可以通过添加一个参数并更改中的Seq来查找第3到第5个匹配项。这里是使用分隔字符串拆分器的另一个选项。已经发布的XML方法是一个很好的方法,但是这种方法不需要表变量 这是作为一个内联表值函数创建的,它应该能够保持非常快的性能
create function fn_getFirstNthSentence
(
@SearchedStr varchar(100)
, @Occurrence int
, @Delimiter char(1)
) returns table as return
with ParsedValues as
(
select Item
, ItemNumber
from dbo.DelimitedSplit8K(@SearchedStr, @Delimiter)
where ItemNumber <= @Occurrence
)
select top 1 ResultString = STUFF(
(
select @Delimiter + Item
from ParsedValues
order by ItemNumber
for xml path('')), 1,1, '') + @Delimiter
from ParsedValues
如果你不喜欢杰夫·摩登的拆分器,你可以在这里找到其他几种选择。我并不是什么都用Moden,但是当你需要保持解析值的顺序时,它是很棒的
--编辑--
下面介绍如何将其修改为标量函数,而不是内联表值函数。我倾向于保留itvf,因为它们更快、更灵活
create function fn_getFirstNthSentenceScalar
(
@SearchedStr varchar(100) = 'hello world.It.is.raining.today.this is after 5'
, @Occurrence int = 5
, @Delimiter char(1) = '.'
) returns varchar(max) as begin
declare @RetVal varchar(max);
with ParsedValues as
(
select Item
, ItemNumber
from dbo.DelimitedSplit8K(@SearchedStr, @Delimiter)
where ItemNumber <= @Occurrence
)
select top 1 @RetVal = STUFF(
(
select @Delimiter + Item
from ParsedValues
order by ItemNumber
for xml path('')), 1,1, '') + @Delimiter
from ParsedValues;
return @RetVal
end
创建函数fn\u getFirstNthSentenceScalar
(
@SearchedStr varchar(100)=“你好,世界。它。正在下雨。今天。这是5点之后”
,@Occurrence int=5
,@分隔符字符(1)='.'
)返回varchar(max)作为开始
声明@RetVal varchar(最大值);
使用parsedValue作为
(
选择项
,项目编号
来自dbo.DelimitedSplit8K(@SearchedStr,@Delimiter)
其中ItemNumber这里是另一个使用分隔字符串拆分器的选项。已经发布的XML方法是一个很好的方法,但这种方法不需要表变量
这是作为一个内联表值函数创建的,它应该能够保持非常快的性能
create function fn_getFirstNthSentence
(
@SearchedStr varchar(100)
, @Occurrence int
, @Delimiter char(1)
) returns table as return
with ParsedValues as
(
select Item
, ItemNumber
from dbo.DelimitedSplit8K(@SearchedStr, @Delimiter)
where ItemNumber <= @Occurrence
)
select top 1 ResultString = STUFF(
(
select @Delimiter + Item
from ParsedValues
order by ItemNumber
for xml path('')), 1,1, '') + @Delimiter
from ParsedValues
如果你不喜欢Jeff Moden的拆分器,你可以在这里找到其他几个选项。我不是什么都用Moden的,但是当你需要保持解析值的顺序时,它是很棒的
--编辑--
下面是如何将其修改为标量函数,而不是内联表值函数。我的首选是保留itvf,因为它们更快、更灵活
create function fn_getFirstNthSentenceScalar
(
@SearchedStr varchar(100) = 'hello world.It.is.raining.today.this is after 5'
, @Occurrence int = 5
, @Delimiter char(1) = '.'
) returns varchar(max) as begin
declare @RetVal varchar(max);
with ParsedValues as
(
select Item
, ItemNumber
from dbo.DelimitedSplit8K(@SearchedStr, @Delimiter)
where ItemNumber <= @Occurrence
)
select top 1 @RetVal = STUFF(
(
select @Delimiter + Item
from ParsedValues
order by ItemNumber
for xml path('')), 1,1, '') + @Delimiter
from ParsedValues;
return @RetVal
end
创建函数fn\u getFirstNthSentenceScalar
(
@SearchedStr varchar(100)=“你好,世界。它。正在下雨。今天。这是5点之后”
,@Occurrence int=5
,@分隔符字符(1)='.'
)返回varchar(max)作为开始
声明@RetVal varchar(最大值);
使用parsedValue作为
(
选择项
,项目编号
来自dbo.DelimitedSplit8K(@SearchedStr,@Delimiter)
其中ItemNumber如果您的代码运行时没有错误,那么您会感到很荣幸,但您可能想发布。SQL Server非常擅长处理数据,但不擅长字符串操作。您可以使用t-SQL来加快这一速度,但我认为任何SQL在这类事情上都不会比CLR更快。@AndrewDeighton SQL Server不支持正则表达式表达式。它可以处理一些基本的模式匹配,但不能处理完整的正则表达式。听起来好像你在试图解决
create function fn_getFirstNthSentence
(
@SearchedStr varchar(100)
, @Occurrence int
, @Delimiter char(1)
) returns table as return
with ParsedValues as
(
select Item
, ItemNumber
from dbo.DelimitedSplit8K(@SearchedStr, @Delimiter)
where ItemNumber <= @Occurrence
)
select top 1 ResultString = STUFF(
(
select @Delimiter + Item
from ParsedValues
order by ItemNumber
for xml path('')), 1,1, '') + @Delimiter
from ParsedValues
declare @String varchar(100) = 'hello world.It.is.raining.today.'
, @Num int = 3
, @Delimiter char(1) = '.'
;
select *
from fn_getFirstNthSentence(@String, @Num, @Delimiter)
create function fn_getFirstNthSentenceScalar
(
@SearchedStr varchar(100) = 'hello world.It.is.raining.today.this is after 5'
, @Occurrence int = 5
, @Delimiter char(1) = '.'
) returns varchar(max) as begin
declare @RetVal varchar(max);
with ParsedValues as
(
select Item
, ItemNumber
from dbo.DelimitedSplit8K(@SearchedStr, @Delimiter)
where ItemNumber <= @Occurrence
)
select top 1 @RetVal = STUFF(
(
select @Delimiter + Item
from ParsedValues
order by ItemNumber
for xml path('')), 1,1, '') + @Delimiter
from ParsedValues;
return @RetVal
end