Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 优化查找字符串中第n次出现的字符_Sql Server - Fatal编程技术网

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

我编写了一个sql server函数,它在第n个字符出现之前返回子字符串

比如说,,
选择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