CHARINDEX(、PATINDEX 和 LIKE)在 T-SQL 函数中返回误报

CHARINDEX (, PATINDEX, and LIKE) returning false positives in T-SQL function

我有一个如下所列的 T-SQL 函数,当特定子字符串在目标字符串中时,它需要 return 一个特定值。

我已经尝试对此进行研究,但我发现它是 CHARINDEX(string, searchstring)(似乎是正确的)还是 CHARINDEX(searchstring, string) 存在不一致之处,并查看了 LIKE ] 和 PATINDEX 个备选方案。

这三种方法在明显的情况下都导致不匹配(很可能我只是做错了什么),或者它有效,但也给出了误报。

在下面的示例中,大小写“1ST”和“10ST”都 return 就好像两者都被发现一样,就好像它是“1ST10ST”一样。

我确定这是我遗漏的一些简单格式,如果您能指出错误的话。

欢迎回答 LIKECHARINDEXPATINDEX

函数:

CREATE OR ALTER FUNCTION SDACalculateAttributeStaticBonus
    (@intAttribute VARCHAR)
RETURNS int
BEGIN
    DECLARE @intRunningTotal int = 0;

    IF( CHARINDEX(@intAttribute, '1ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 1;
    END

    IF( CHARINDEX(@intAttribute, '2ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 2;
    END

    IF( CHARINDEX(@intAttribute, '3ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 3;
    END

    IF( CHARINDEX(@intAttribute, '4ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 4;
    END

    IF( CHARINDEX(@intAttribute, '5ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 5;
    END

    IF( CHARINDEX(@intAttribute, '6ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 6;
    END

    IF( CHARINDEX(@intAttribute, '7ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 7;
    END

    IF( CHARINDEX(@intAttribute, '8ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 8;
    END

    IF( CHARINDEX(@intAttribute, '9ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 9;
    END

    IF( CHARINDEX(@intAttribute, '10ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 10;
    END

    RETURN @intRunningTotal;
END

当前测试语句(以防万一它们有误):

SELECT DISTINCT '1ST' AS Strength, dbo.SDACalculateAttributeStaticBonus('1ST') AS StrengthBonus
FROM HeroesViewMultiLine

SELECT DISTINCT '2ST' AS Strength, dbo.SDACalculateAttributeStaticBonus('2ST') AS StrengthBonus
FROM HeroesViewMultiLine

SELECT DISTINCT '3ST' AS Strength, dbo.SDACalculateAttributeStaticBonus('3ST') AS StrengthBonus
FROM HeroesViewMultiLine

SELECT DISTINCT '4ST' AS Strength, dbo.SDACalculateAttributeStaticBonus('4ST') AS StrengthBonus
FROM HeroesViewMultiLine

SELECT DISTINCT '5ST' AS Strength, dbo.SDACalculateAttributeStaticBonus('5ST') AS StrengthBonus
FROM HeroesViewMultiLine

SELECT DISTINCT '6ST' AS Strength, dbo.SDACalculateAttributeStaticBonus('6ST') AS StrengthBonus
FROM HeroesViewMultiLine

SELECT DISTINCT '7ST' AS Strength, dbo.SDACalculateAttributeStaticBonus('7ST') AS StrengthBonus
FROM HeroesViewMultiLine

SELECT DISTINCT '8ST' AS Strength, dbo.SDACalculateAttributeStaticBonus('8ST') AS StrengthBonus
FROM HeroesViewMultiLine

SELECT DISTINCT '9ST' AS Strength, dbo.SDACalculateAttributeStaticBonus('9ST') AS StrengthBonus
FROM HeroesViewMultiLine

SELECT DISTINCT '10ST' AS Strength, dbo.SDACalculateAttributeStaticBonus('10ST') AS StrengthBonus
FROM HeroesViewMultiLine

因为您的参数长度可能声明为大于您的输入字符串长度,否则默认值为 1。

除此之外,我会用ELSE IF代替你的多个IF,因为它可以获得更好的性能。

create or alter FUNCTION SDACalculateAttributeStaticBonus(
    @intAttribute VARCHAR(10)
)
RETURNS int
BEGIN
    DECLARE @intRunningTotal int = 0;

    IF( CHARINDEX(@intAttribute, '1ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 1;
    END

    ELSE IF( CHARINDEX(@intAttribute, '2ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 2;
    END

    ELSE IF( CHARINDEX(@intAttribute, '3ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 3;
    END

    ELSE IF( CHARINDEX(@intAttribute, '4ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 4;
    END

    ELSE IF( CHARINDEX(@intAttribute, '5ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 5;
    END

    ELSE IF( CHARINDEX(@intAttribute, '6ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 6;
    END

    ELSE IF( CHARINDEX(@intAttribute, '7ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 7;
    END

    ELSE IF( CHARINDEX(@intAttribute, '8ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 8;
    END

    ELSE IF( CHARINDEX(@intAttribute, '9ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 9;
    END

    ELSE IF( CHARINDEX(@intAttribute, '10ST') > 0 )
    BEGIN
        SET @intRunningTotal = @intRunningTotal + 10;
    END

    RETURN @intRunningTotal;
END

除了没有定义参数长度的问题之外,我不会实现这样的逻辑——或者根本不会实现标量 UDF。

虽然您没有显示它,但大概是因为您的函数正在针对每种情况进行测试,所以您可以传递一个包含多个要求和的限定值的字符串。

您应该始终尝试编写速度快几个数量级的 table 值 函数,尤其是在使用较大的结果集时。

根据您展示的内容,尝试以下操作:

create or alter function SDACalculateAttributeStaticBonus (@intAttribute varchar(50))
returns table
as
return (
    select [Value]=Sum(try_convert(int,value))
    from string_split(replace(@intAttribute, 'ST', ','), ',')
);

像使用任何其他 table 和 select 一样使用它,加入应用它:

select [Value] from dbo.SDACalculateAttributeStaticBonus('10ST');

结果:10

select [value] from dbo.SDACalculateAttributeStaticBonus('1ST2ST3ST');

结果:6

SELECT DISTINCT '10ST' AS Strength, b.[value] AS StrengthBonus
FROM HeroesViewMultiLine
CROSS APPLY dbo.SDACalculateAttributeStaticBonus('10ST')b;