私が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
さて、これがこれまでの私の解決策です:
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
最終的に、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
のみを計算できます。