优化查找字符串中第N个字符的出现次数

时间:2016-07-29 13:11:41

标签: sql-server

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

例如, $( function () { //wait for document to be ready $(".anchorShow").on("click", function (evt) { //bind the click event to the anchors evt.preventDefault(); //stop click var anchor = $(this); //link that was clicked var wrapper = anchor.closest(".MainOuterDiv"); //parent element that wraps content wrapper.find(".IntroductionDiv").show(); //show intro wrapper.find(".FeaturesDiv").hide(); //hide features }); }); 回报'hello world.It.Is。'结果。

我写的函数看起来很脏而且很慢,所以我想优化它。 任何建议让它清洁是值得赞赏的。

谢谢。

SELECT dbo.fn_getFirstNthSentence('.', 'hello world.It.is.raining.today', 3)

3 个答案:

答案 0 :(得分:1)

- 我发现这些功能是一个雷区,并且冒着踩到矿井的风险,我尝试了一些简化 - 可能是性能的微观改进

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;

答案 1 :(得分:1)

另一种选择是通过XML

我无法看到您的基准测试,但它的代码肯定要少得多。添加选项可以是通过添加参数并将 Where Seq&lt; = @ FindPos 更改为其中Seq介于range1和range2 之间来查找第3到第5次。

Declare @FindPos int = 3
Declare @String  varchar(max) = 'hello world.It.is.raining.today'
Declare @Delim   varchar(10)  = '.'


Declare @XML xml,@RetVal varchar(max) = ''
Set @XML = Cast('<x>' + Replace(@String,@Delim,'</x><x>')+'</x>' as XML)

Declare @Table table (Seq int identity(1,1),String varchar(max))
Insert Into @Table Select ltrim(rtrim(String.value('.', 'varchar(max)')))+@Delim as value FROM @XML.nodes('x') as T(String)

Select @RetVal=@RetVal + String from @Table Where Seq<=@FindPos Order By Seq

Select @RetVal

返回

hello world.It.is.
  

编辑:如果有帮助,下面是我的通用解析函数,它返回一个   标准化表...

CREATE FUNCTION [dbo].[udf-Str-Parse] (@String varchar(max),@Delimeter varchar(10))
--Usage: Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',')
--       Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ')
--       Select * from [dbo].[udf-Str-Parse]('id26,id46|id658,id967','|')
--       Select * from [dbo].[udf-Str-Parse]('hello world. It. is. . raining.today','.')

Returns @ReturnTable Table (Key_PS int IDENTITY(1,1), Key_Value varchar(max))
As
Begin
   Declare @XML xml;Set @XML = Cast('<x>' + Replace(@String,@Delimeter,'</x><x>')+'</x>' as XML)
   Insert Into @ReturnTable Select Key_Value = ltrim(rtrim(String.value('.', 'varchar(max)'))) FROM @XML.nodes('x') as T(String)
   Return 
End

例如:

Select * from [dbo].[udf-Str-Parse]('hello world.It.is.raining.today','.')

返回

Key_PS  Key_Value
1       hello world
2       It
3       is
4       raining
5       today

答案 2 :(得分:1)

这是使用分隔字符串拆分器的另一种选择。已发布的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创建的分离器。它有一个功能,即其他分离器都没有...一列来指示值来自哪个位置。你可以在这里找到他的文章。 http://www.sqlservercentral.com/articles/Tally+Table/72993/

然后,如果你想执行它,你可以很简单地做到这一点。

declare @String varchar(100) = 'hello world.It.is.raining.today.'
    , @Num int = 3
    , @Delimiter char(1) = '.'
;

select *
from fn_getFirstNthSentence(@String, @Num, @Delimiter)

如果你不喜欢Jeff Moden的分配器,你可以在这里找到其他几种选择。 http://sqlperformance.com/2012/07/t-sql-queries/split-strings我不会使用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