是否有可能在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