web-dev-qa-db-ja.com

T-SQL2つの文字列の文字一致のパーセンテージを取得します

私が2つの単語のセットを持っているとしましょう:

アレクサンダーとアレキサンダーORアレクサンダーとアレグザンダー

AlexanderとAleaxnder、またはその他の組み合わせ。一般に、単語または単語のセットを入力する際の人為的エラーについて話します。

私が達成したいのは、2つの文字列の文字の一致率を取得することです。

これが私がこれまでに持っているものです:

    DECLARE @table1 TABLE
(
  nr INT
  , ch CHAR
)

DECLARE @table2 TABLE
(
  nr INT
  , ch CHAR
)


INSERT INTO @table1
SELECT nr,ch FROM  [dbo].[SplitStringIntoCharacters] ('Word w') --> return a table of characters(spaces included)

INSERT INTO @table2
SELECT nr,ch FROM  [dbo].[SplitStringIntoCharacters] ('Word 5')

DECLARE @resultsTable TABLE
( 
 ch1 CHAR
 , ch2 CHAR
)
INSERT INTO @resultsTable
SELECT DISTINCt t1.ch ch1, t2.ch ch2 FROM @table1 t1
FULL JOIN @table2 t2 ON  t1.ch = t2.ch  --> returns both matches and missmatches

SELECT * FROM @resultsTable
DECLARE @nrOfMathches INT, @nrOfMismatches INT, @nrOfRowsInResultsTable INT
SELECT  @nrOfMathches = COUNT(1) FROM  @resultsTable WHERE ch1 IS NOT NULL AND ch2 IS NOT NULL
SELECT @nrOfMismatches = COUNT(1) FROM  @resultsTable WHERE ch1 IS NULL OR ch2 IS NULL


SELECT @nrOfRowsInResultsTable = COUNT(1)  FROM @resultsTable


SELECT @nrOfMathches * 100 / @nrOfRowsInResultsTable

SELECT * FROM @resultsTableは次を返します。

ch1         ch2
NULL        5
[blank]     [blank] 
D           D
O           O
R           R
W           W
17
Dragos Durlut

さて、これがこれまでの私の解決策です:

SELECT  [dbo].[GetPercentageOfTwoStringMatching]('valentin123456'  ,'valnetin123456')

86%を返します

CREATE FUNCTION [dbo].[GetPercentageOfTwoStringMatching]
(
    @string1 NVARCHAR(100)
    ,@string2 NVARCHAR(100)
)
RETURNS INT
AS
BEGIN

    DECLARE @levenShteinNumber INT

    DECLARE @string1Length INT = LEN(@string1)
    , @string2Length INT = LEN(@string2)
    DECLARE @maxLengthNumber INT = CASE WHEN @string1Length > @string2Length THEN @string1Length ELSE @string2Length END

    SELECT @levenShteinNumber = [dbo].[LEVENSHTEIN] (   @string1  ,@string2)

    DECLARE @percentageOfBadCharacters INT = @levenShteinNumber * 100 / @maxLengthNumber

    DECLARE @percentageOfGoodCharacters INT = 100 - @percentageOfBadCharacters

    -- Return the result of the function
    RETURN @percentageOfGoodCharacters

END




-- =============================================     
-- Create date: 2011.12.14
-- Description: http://blog.sendreallybigfiles.com/2009/06/improved-t-sql-levenshtein-distance.html
-- =============================================

CREATE FUNCTION [dbo].[LEVENSHTEIN](@left  VARCHAR(100),
                                    @right VARCHAR(100))
returns INT
AS
  BEGIN
      DECLARE @difference    INT,
              @lenRight      INT,
              @lenLeft       INT,
              @leftIndex     INT,
              @rightIndex    INT,
              @left_char     CHAR(1),
              @right_char    CHAR(1),
              @compareLength INT

      SET @lenLeft = LEN(@left)
      SET @lenRight = LEN(@right)
      SET @difference = 0

      IF @lenLeft = 0
        BEGIN
            SET @difference = @lenRight

            GOTO done
        END

      IF @lenRight = 0
        BEGIN
            SET @difference = @lenLeft

            GOTO done
        END

      GOTO comparison

      COMPARISON:

      IF ( @lenLeft >= @lenRight )
        SET @compareLength = @lenLeft
      ELSE
        SET @compareLength = @lenRight

      SET @rightIndex = 1
      SET @leftIndex = 1

      WHILE @leftIndex <= @compareLength
        BEGIN
            SET @left_char = substring(@left, @leftIndex, 1)
            SET @right_char = substring(@right, @rightIndex, 1)

            IF @left_char <> @right_char
              BEGIN -- Would an insertion make them re-align?
                  IF( @left_char = substring(@right, @rightIndex + 1, 1) )
                    SET @rightIndex = @rightIndex + 1
                  -- Would an deletion make them re-align?
                  ELSE IF( substring(@left, @leftIndex + 1, 1) = @right_char )
                    SET @leftIndex = @leftIndex + 1

                  SET @difference = @difference + 1
              END

            SET @leftIndex = @leftIndex + 1
            SET @rightIndex = @rightIndex + 1
        END

      GOTO done

      DONE:

      RETURN @difference
  END 
28
Dragos Durlut

最終的に、2つの文字列が互いに「あいまい」に一致する可能性を解決しようとしているように見えます。

SQLは、それを実行する効率的で最適化された組み込み関数を提供し、おそらくあなたが書いたものよりも優れたパフォーマンスを発揮します。探している2つの関数は [〜#〜] soundex [〜#〜][〜#〜] Difference [〜#〜] です。

どちらも正確にあなたが求めたものを解決しませんが-つまり、パーセンテージの一致を返しません-私は彼らがあなたが最終的に達成しようとしていることを解決すると信じています。

SOUNDEXは、Wordの最初の文字である4文字のコードと、Wordのサウンドパターンを表す3つの数字のコードを返します。次のことを考慮してください。

SELECT SOUNDEX('Alexander')
SELECT SOUNDEX('Alegzander')
SELECT SOUNDEX('Owleksanndurr')
SELECT SOUNDEX('Ulikkksonnnderrr')
SELECT SOUNDEX('Jones')

/* Results:

A425
A425
O425
U425
J520

*/

お気づきのことと思いますが、3桁の数字425は、ほぼ同じように聞こえるすべての数字で同じです。したがって、それらを簡単に一致させて、「「Owleksanndurr」と入力しました。おそらく「Alexander」を意味しましたか?」と言うことができます。

さらに、2つの文字列間のDIFFERENCEの不一致を比較し、スコアを与えるSOUNDEX関数があります。

SELECT DIFFERENCE(  'Alexander','Alexsander')
SELECT DIFFERENCE(  'Alexander','Owleksanndurr')
SELECT DIFFERENCE(  'Alexander', 'Jones')
SELECT DIFFERENCE(  'Alexander','ekdfgaskfalsdfkljasdfl;jl;asdj;a')

/* Results:

4
3
1
1     

*/

ご覧のとおり、スコアが低いほど(0から4の間)、文字列が一致する可能性が高くなります。

SOUNDEXに対するDIFFERENCEの利点は、本当に頻繁なあいまいマッチングを行う必要がある場合、SOUNDEXデータを別の(インデックス可能な)列に格納してインデックスを付けることができることです。 DIFFERENCEは、比較時にSOUNDEXのみを計算できます。

11