我一直在尝试编写一个函数来检查字符串是否包含一个数字,而该数字不是更大数字的一部分(换句话说,如果要搜索的数字是'6'并且字符串是'7+16+2'它应该返回 false,因为这个字符串中的 '6' 是数字 '16' 的一部分)
我写了下面的函数(它很长,但我会在重构之前先测试它)
经过测试,我发现了一个错误,它仅通过逻辑运行找到的数字的第一个实例。因此,使用 '6' 对 '16+7+9+6' 运行此函数将返回 false,因为它确定第一个 '6' 是更大数字的一部分并停止处理。
我认为要解决这个问题,我必须实现一个循环来缩短“haystack”字符串(这样,使用示例“16+7+9+6”,函数在消除后继续检查“+7+9+6”第一个'6')但在花时间使已经复杂的功能更加复杂之前,我想检查是否有更简单的方法来实现相同的目标?
drop function dbo.runners_contain_runner
go
create function dbo.runners_contain_runner(@runner varchar(max), @runners varchar(max))
returns int
as
begin
/*
eliminate the plus sign from @runners so that the
'isnumeric' function doesn't return false positives (it returns 1 for '+')
*/
set @runners = replace(@runners,'+','_' )
declare @ret int;
set @ret = 0;
-- if the runner is the only runner return 1
if @runners = @runner
set @ret = 1
else
begin
declare @charindex int;
set @charindex = charindex(@runner,@runners)
if @charindex > 0
begin
-- if it is at the beginning then check the char after it
if @charindex = 1
begin
if isnumeric(substring(@runners,@charindex + len(@runner),1)) = 0
set @ret = @charindex
end
-- if it is at the end then check the char before it
else if @charindex = len(@runners) - (len(@runner) - 1)
begin
if isnumeric(substring(@runners,@charindex - 1,1)) = 0
set @ret = @charindex
end
-- if it is in the middle check the chars either side of it
else
begin
if isnumeric(substring(@runners,@charindex - 1,1)) +
isnumeric(substring(@runners,@charindex + len(@runner),1)) = 0
set @ret = @charindex
end
end
end
return @ret
end
也许您过于关注想要一个数字,从而使问题变得过于复杂。退后一步。你真正想要的是一个两边都没有任何数字的子字符串。一个数字可以成为更大数字的一部分的唯一方法是在它的两侧至少有一个数字,对吗?所以只要你只传入数字,那么这个定义仍然应该产生两边都没有任何数字的数字。
考虑到这一点,我们只需要 3 个
PATINDEX
谓词来覆盖传入的值在最左边、最右边或中间。尝试以下方法,因为它似乎有效:然后测试:
有 3 个变体的原因
PATINDEX
是PATINDEX
搜索模式不是正则表达式 (RegeEx),这与许多人所说/认为的相反(与LIKE
模式相同)。PATINDEX
并且LIKE
模式没有量词,因此无法指定[^0123456789]
单个字符替换应为“0 或更多”;它是“一个,只有一个;不多也不少”。强制二进制排序规则(即
COLLATE Latin1_General_100_BIN2
在每个@Runner
引用之后)确保我们只处理这 10 个十进制数字,而不是任何其他可能被视为等效的字符要将上述逻辑放入内联表值函数 (TVF) 中,使其更易于使用(并且比类似易于使用的标量 UDF 更高效),请尝试以下操作:
然后测试:
返回:
从那以后,我重新编写了我的函数,如下所示。
编辑:我在看到 Solomon Rutzky 对我的问题的回复之前完成了这个。他的回复有效,比我的要好。但我会留下这个答案作为替代。