相关文章推荐
会搭讪的骆驼  ·  sqlServer ...·  9 月前    · 
豁达的红烧肉  ·  SQL Server ...·  1 年前    · 
奔放的萝卜  ·  CHARINDEX ...·  1 年前    · 
谈吐大方的斑马  ·  Intent.GetParcelableAr ...·  1 年前    · 
急躁的数据线  ·  用AI(chat gpt) ...·  1 年前    · 

在T-SQL函数中,CHARINDEX(, PATINDEX, 和 LIKE)返回错误信息

1 人不认可

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

我试图研究这个问题,但是我看到不一致的地方,是 CHARINDEX(string, searchstring) (似乎是正确的)还是 CHARINDEX(searchstring, string) ,并且研究了 LIKE PATINDEX 的替代品。

所有这三种方法在明显的情况下都没有匹配结果(很可能我只是做错了什么),或者它起作用了,但也给出了假阳性结果。

在下面的例子中,案例'1ST'和'10ST'都返回,好像都是找到了'1ST10ST'。

我相信是我错过了一些简单的格式,如果你能指出错误。

欢迎回答 LIKE CHARINDEX PATINDEX 的问题。

CREATE OR ALTER FUNCTION SDACalculateAttributeStaticBonus
    (@intAttribute VARCHAR)
RETURNS int
BEGIN
DECLARE @intRunningTotal int = 0;
    IF( CHARINDEX(@intAttribute, '1ST') > 0 )
    BEGIN
SET @intRunningTotal = @intRunningTotal + 1;
    IF( CHARINDEX(@intAttribute, '2ST') > 0 )
    BEGIN
SET @intRunningTotal = @intRunningTotal + 2;
    IF( CHARINDEX(@intAttribute, '3ST') > 0 )
    BEGIN
SET @intRunningTotal = @intRunningTotal + 3;
    IF( CHARINDEX(@intAttribute, '4ST') > 0 )
    BEGIN
SET @intRunningTotal = @intRunningTotal + 4;
    IF( CHARINDEX(@intAttribute, '5ST') > 0 )
    BEGIN
SET @intRunningTotal = @intRunningTotal + 5;
    IF( CHARINDEX(@intAttribute, '6ST') > 0 )
    BEGIN
SET @intRunningTotal = @intRunningTotal + 6;
    IF( CHARINDEX(@intAttribute, '7ST') > 0 )
    BEGIN
SET @intRunningTotal = @intRunningTotal + 7;
    IF( CHARINDEX(@intAttribute, '8ST') > 0 )
    BEGIN
SET @intRunningTotal = @intRunningTotal + 8;
    IF( CHARINDEX(@intAttribute, '9ST') > 0 )
    BEGIN
SET @intRunningTotal = @intRunningTotal + 9;
    IF( CHARINDEX(@intAttribute, '10ST') > 0 )
    BEGIN
SET @intRunningTotal = @intRunningTotal + 10;
RETURN @intRunningTotal;

当前的测试语句(以防它们以某种方式出错)。

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
2 个评论
要改掉的坏习惯:在声明VARCHAR时不加(length) --你 应该 为你使用的任何 varchar 变量和参数提供一个长度--否则,你最终会得到一个长度为 1 字符 - 通常这 不是 你想要的 !
调试提示:将你的函数主体改为 RETURN (LEN(@intAttribute)) ,你应该看到问题所在。
sql-server
function
tsql
charindex
Kamurai
Kamurai
发布于 2022-04-02
2 个回答
Stu
Stu
发布于 2022-04-02
已采纳
0 人赞同

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

虽然你没有显示出来,但据推测,由于你的函数是针对每一种情况进行测试的,你可以传递一个有多个限定值的字符串,你想对其进行求和。

你应该总是尝试编写 表值 函数,这些函数的速度要快几个数量级,特别是在使用较大的结果集时。

根据你所展示的内容,请尝试以下内容。

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

像其他表格一样使用,并从中选择连接到它或应用它。

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;
谢谢你,这可能对今后的工作很有用。 还有其他一些代码需要考虑,但沿着创建临时表进行匹配的思路做一些事情,至少会更有效率。
Stu
是的,如果你能建立一个列表,你可以以基于集合的方式加入,这将永远比使用标量函数的迭代步骤要好。
D-Shih
D-Shih
发布于 2022-04-02
0 人赞同

因为你的参数长度可能被声明为高于你的输入字符串长度,否则它将是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;
ELSE IF( CHARINDEX(@intAttribute, '2ST') > 0 )
    BEGIN
SET @intRunningTotal = @intRunningTotal + 2;
ELSE IF( CHARINDEX(@intAttribute, '3ST') > 0 )
    BEGIN
SET @intRunningTotal = @intRunningTotal + 3;
ELSE IF( CHARINDEX(@intAttribute, '4ST') > 0 )
    BEGIN
SET @intRunningTotal = @intRunningTotal + 4;
ELSE IF( CHARINDEX(@intAttribute, '5ST') > 0 )
    BEGIN
SET @intRunningTotal = @intRunningTotal + 5;
ELSE IF( CHARINDEX(@intAttribute, '6ST') > 0 )
    BEGIN
SET @intRunningTotal = @intRunningTotal + 6;
ELSE IF( CHARINDEX(@intAttribute, '7ST') > 0 )
    BEGIN
SET @intRunningTotal = @intRunningTotal + 7;
ELSE IF( CHARINDEX(@intAttribute, '8ST') > 0 )
    BEGIN
SET @intRunningTotal = @intRunningTotal + 8;
ELSE IF( CHARINDEX(@intAttribute, '9ST') > 0 )
    BEGIN
SET @intRunningTotal = @intRunningTotal + 9;
ELSE IF( CHARINDEX(@intAttribute, '10ST') > 0 )
    BEGIN