是否有可能在MySQL中從表中選擇與給定字符串只有一個字符差異的所有字符串?MySQL:如何有效地選擇只有一個字符差異的字符串?
例如。 Iphone 5
和Iphone 5s
或Model x-1
和Models x1
是否有可能在MySQL中從表中選擇與給定字符串只有一個字符差異的所有字符串?MySQL:如何有效地選擇只有一個字符差異的字符串?
例如。 Iphone 5
和Iphone 5s
或Model x-1
和Models x1
如果你可以添加一個用戶函數到MySQL,那麼你可以使用萊文斯坦的距離。代碼見this other question。例如,您可以查詢WHERE LEVENSHTEIN(description, 'iphone 5') <= 2
。你會發現「iPhone 5S」,也可能是「ipohne 5」,這可能是一個加號。
否則,具體個案很容易(例如,REGEX 'iphone.*'
或類似),但一般情況下將是一個噩夢實施。
該版本被修改爲接受第三個參數MAXCOST。當達到levenshtein子循環的最大成本時,搜索功能將簡單地中止。排除病理情況,並記住實際成本可能稍微偏離(即排除12的成本可能包括成本爲12的字符串,排除成本爲11的字符串),這會減少其中Levenshtein距離不合理。這些案件可能對你沒有興趣。
所以如果你想要距離小於3的字符串,你可以使用WHERE levenshtein(string1, string2, 4) < 3
。距離3-4或以上的所有字符串現在將立即返回4 ,並被排除。
測試:
mysql> select BENCHMARK(1000,levenshtein('PIPPORIDICOLO','LUKASPERICOLO', 99));
+------------------------------------------------------------------+
| BENCHMARK(1000,levenshtein('PIPPORIDICOLO','LUKASPERICOLO', 99)) |
+------------------------------------------------------------------+
| 0 |
+------------------------------------------------------------------+
1 row in set (2.50 sec)
mysql> select BENCHMARK(1000,levenshtein('PIPPORIDICOLO','LUKASPERICOLO', 3));
+-----------------------------------------------------------------+
| BENCHMARK(1000,levenshtein('PIPPORIDICOLO','LUKASPERICOLO', 3)) |
+-----------------------------------------------------------------+
| 0 |
+-----------------------------------------------------------------+
1 row in set (0.08 sec)
這裏的成本爲2500減少到80毫秒每1000次評估。
這是修改後的代碼。在定義這個新的函數之前,您必須先刪除舊的函數,除非您更改名稱。
DELIMITER $$
CREATE FUNCTION levenshtein(s1 VARCHAR(255), s2 VARCHAR(255), maxcost INTEGER)
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE s1_len, s2_len, i, j, c, c_temp, cost INT;
DECLARE s1_char CHAR;
-- max strlen=255
DECLARE cv0, cv1 VARBINARY(256);
SET s1_len = CHAR_LENGTH(s1), s2_len = CHAR_LENGTH(s2), cv1 = 0x00, j = 1, i = 1, c = 0;
IF s1 = s2 THEN
RETURN 0;
ELSEIF s1_len = 0 THEN
RETURN s2_len;
ELSEIF s2_len = 0 THEN
RETURN s1_len;
ELSE
WHILE j <= s2_len DO
SET cv1 = CONCAT(cv1, UNHEX(HEX(j))), j = j + 1;
END WHILE;
WHILE i <= s1_len DO
SET s1_char = SUBSTRING(s1, i, 1), c = i, cv0 = UNHEX(HEX(i)), j = 1;
WHILE j <= s2_len DO
SET c = c + 1;
IF c > maxcost THEN
RETURN maxcost;
END IF;
IF s1_char = SUBSTRING(s2, j, 1) THEN
SET cost = 0;
ELSE
SET cost = 1;
END IF;
SET c_temp = CONV(HEX(SUBSTRING(cv1, j, 1)), 16, 10) + cost;
IF c > c_temp THEN SET c = c_temp; END IF;
SET c_temp = CONV(HEX(SUBSTRING(cv1, j+1, 1)), 16, 10) + 1;
IF c > c_temp THEN SET c = c_temp; END IF;
SET cv0 = CONCAT(cv0, UNHEX(HEX(c))), j = j + 1;
END WHILE;
SET cv1 = cv0, i = i + 1;
END WHILE;
END IF;
RETURN c;
END$$
DELIMITER ;
這個字符的差異必須在字符串的末尾嗎? – Mureinik
沒有。可以在字符串的任何位置 – Francesco
這取決於,你的意思是1個字符的區別。檢查[這個答案](http://stackoverflow.com/questions/3338889/how-to-find-similar-results-and-sort-by-similarity)。 – Nosyara