我的SQL函数没有返回我期望的值

时间:2014-09-15 23:00:35

标签: sql tsql return-value

这是我第一次尝试SQL函数。我在VB中写了它,它就像一个魅力。当我将它翻译为SQL Server时,它不会返回我所期望的。该函数的目的是返回两个字符串的百分比匹配。

我期望它如何运作是这样的:

  1. 接受两个字符串,比较两个字符串,并根据我的评级值,返回匹配值的百分比... matchscore / max possiblescore
  2. 较大字符串的长度乘以3.这是最大可能分数。
  3. 逐个字符转到第一个字符串,并在第二个字符串中找到该字符。
  4. 如果在第二个字符串中的相同位置找到该字符,请将3添加到匹配分数并继续下一个字母。
  5. 如果在第二个单词中找到该字符,但不在同一个位置,请添加一个匹配分数并转到下一个字符。
  6. 如果在第二个字符串中找不到该字符,则不添加任何内容并转到下一个字符。
  7. 将匹配分数除以最大可能分数。这将返回一个十进制值。我读RETURN只返回一个整数,所以我将除法结果乘以100。
  8. 我期望的一个例子是我将“CAT”与“CART”进行比较。我的预期回报是7/12 ...... 0.58。相反,我得到0.如果我将“CAT”与“CAT”进行比较,我期望9/9 ... 1.00。相反,我得到了2.

    (2014年9月17日的注意事项:感谢您的意见。我使用了您的建议,并做了一个重大改变,这不会影响我的要求,除了得到正确的最终答案是我摆脱了第二个While循环。相反,我在@ strWord2中搜索@strLetter。如果找到它,那么,我看看它是否与@ strWord1在@ strWord2中的位置相同。如果是,那么我添加3,如果没有,我添加1.这加快了功能并使计数准确。

    以下是代码:

    CREATE FUNCTION [dbo].[CompareWords]
        (@strWord1 VARCHAR(2000), @strWord2 VARCHAR(2000))
    RETURNS DECIMAL
    AS
    BEGIN
       SET @strWord1 = UPPER(@strWord1)
       SET @strWord2 = UPPER(@strWord2)
    
       DECLARE @intLength INT
    
       IF LEN(@strWord1) >= LEN(@strWord2)
       BEGIN
            SET @intLength = LEN(@strWord1)
       END
       ELSE
       BEGIN
            SET @intLength = LEN(@strWord2)
       END
    
       DECLARE @iWordLoop1 INT
       DECLARE @iWordLoop2 INT
       DECLARE @intWordLoop2 INT
       DECLARE @intWordScore INT
       DECLARE @intLetterScore INT
    
       SET @intWordScore = 0
       SET @intWordLoop2 = Len(@strWord2)
    
       DECLARE @strLetter VARCHAR(1000)
    
       DECLARE @count1 INT 
       SET @count1 = 0 
    
       SET @iWordLoop1 = Len(@strWord1)
    
       WHILE (@count1 < @iWordLoop1) 
       BEGIN 
           SET @strLetter = SUBSTRING(@strWord1, @count1+1, 1)
           SET @intLetterScore = 0
    
           DECLARE @count2 INT 
           SET @count2 = 0 
    
           SET @iWordLoop2 = Len(@strWord2)
    
           WHILE (@count2 < @iWordLoop2) 
           BEGIN
               If @strLetter = SUBSTRING(@strWord2, @count2+1, 1) 
               BEGIN
                    If @iWordLoop1 = @iWordLoop2 
                    BEGIN
                            SET @intLetterScore = 3
                            SET @iWordLoop2 = Len(@strWord2)
                    END
                    ELSE
                    BEGIN
                            SET @intLetterScore = 1
                    END
               END
    
               SET @intWordScore = @intWordScore + @intLetterScore
               SET @count2 = (@count2 + 1) 
            END
    
           SET @count1 = (@count1 + 1) 
       END 
    
       DECLARE @sinScore DEC
       SET @sinScore = (@intWordScore / (3 * @intLength)) * 100
    
       RETURN @sinSCore
    END;
    

1 个答案:

答案 0 :(得分:1)

我做的最重要的改变是

  1. 在intWordScore计算中使用后,将intLetterScore重置为0。如果没有重置,每次内循环和字符不匹配时都会使用相同的值。
  2. 将乘法乘以100 计算sinScore时的括号 如前一篇文章所述,因为您正在进行整数乘法,所以小数部分会从计算中截断。通过将wordScore增加100倍,它更有可能大于长度并产生非零的结果。
  3. 在括号外乘以乘以除法得分的整数结果乘以长度。如果此答案已经为零,则乘法结果也为零。

    我做的其他更改在代码中被注释:变量intWordLoop2对计算没有影响,可以删除; strLetter可以声明为Char(1)而不是VarChar(1000)。

    CREATE FUNCTION [dbo].[CompareWords]
        (@strWord1 VARCHAR(2000), @strWord2 VARCHAR(2000))
    RETURNS DECIMAL
    AS
    BEGIN
       SET @strWord1 = UPPER(@strWord1)
       SET @strWord2 = UPPER(@strWord2)
    
       --Set @intLength (maxLength as len of word1 or word2)
    DECLARE @intLength INT --maxLength
    IF LEN(@strWord1) >= LEN(@strWord2)
    BEGIN
        SET @intLength = LEN(@strWord1)
    END
    ELSE
    BEGIN
        SET @intLength = LEN(@strWord2)
    END
    
       DECLARE @iWordLoop1 INT, @iWordLoop2 INT--, @intWordLoop2 INT --This variable doesn't impact the calculation 
       DECLARE @intWordScore INT
       DECLARE @intLetterScore INT
    
       SET @intWordScore = 0
       --SET @intWordLoop2 = Len(@strWord2)--this value is not used anywhere else, so removing makes no difference.
    
       --DECLARE @strLetter VARCHAR(1000)
       DECLARE @strLetter CHAR(1)--there is no need for 1000 characters since we're only ever assigning a single character to this
    
       DECLARE @count1 INT 
       SET @count1 = 0 
       SET @iWordLoop1 = Len(@strWord1)
    
       WHILE (@count1 < @iWordLoop1) 
       BEGIN 
           SET @strLetter = SUBSTRING(@strWord1, @count1+1, 1)
           SET @intLetterScore = 0
           DECLARE @count2 INT 
           SET @count2 = 0 
           SET @iWordLoop2 = Len(@strWord2)
    
           WHILE (@count2 < @iWordLoop2) 
           BEGIN
               If @strLetter = SUBSTRING(@strWord2, @count2+1, 1) 
               BEGIN
                    If @iWordLoop1 = @iWordLoop2 
                    BEGIN
                            SET @intLetterScore = 3
                            SET @iWordLoop2 = Len(@strWord2)
                    END
                    ELSE
                    BEGIN
                            SET @intLetterScore = 1
                    END
               END
    
               SET @intWordScore = @intWordScore + @intLetterScore
               SET @intLetterScore = 0
               SET @count2 = (@count2 + 1) 
            END
           SET @count1 = (@count1 + 1) 
       END 
    
       DECLARE @sinScore DEC
       SET @sinScore = (@intWordScore*100 / (3 * @intLength))
    
       RETURN @sinSCore
    END;
    
    
    select dbo.comparewords ('Cat','cart')