MySQL将非数字字符进行比较

我正在寻找与表中匹配用户input的特定号码的logging。 因此,用户可以input12345,但是在数据库中可以是123zz4-5。

我想像这样的东西可以工作,如果PHP函数在MySQL中工作。

SELECT * FROM foo WHERE preg_replace("/[^0-9]/","",bar) = '12345' 

什么是只有MySQL才能做到这一点的等价函数或方法?

我意识到这是一个古老的话题,但是在Google上search这个问题后,我找不到一个简单的解决scheme(我看到了这个可敬的代理商,但认为这是一个更简单的解决scheme),所以这里是我写的一个函数,似乎工作得很好。

 DROP FUNCTION IF EXISTS STRIP_NON_DIGIT; DELIMITER $$ CREATE FUNCTION STRIP_NON_DIGIT(input VARCHAR(255)) RETURNS VARCHAR(255) BEGIN DECLARE output VARCHAR(255) DEFAULT ''; DECLARE iterator INT DEFAULT 1; WHILE iterator < (LENGTH(input) + 1) DO IF SUBSTRING(input, iterator, 1) IN ( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ) THEN SET output = CONCAT(output, SUBSTRING(input, iterator, 1)); END IF; SET iterator = iterator + 1; END WHILE; RETURN output; END $$ 

没有正则expression式replace,只有一个普通的stringREPLACE()。

MySQL有REGEXP运算符,但它只是一个匹配testing程序而不是代替程序,所以你必须把逻辑从头到尾:

 SELECT * FROM foo WHERE bar REGEXP '[^0-9]*1[^0-9]*2[^0-9]*3[^0-9]*4[^0-9]*5[^0-9]*'; 

这就像你喜欢的版本,但更准确地匹配。 两者都会performance同样糟糕,需要一个没有索引的全表扫描。

虽然这不是很好,它显示的结果不匹配,这有助于:

 SELECT * FROM foo WHERE bar LIKE = '%1%2%3%4%5%' 

我仍然想find类似于原始问题中的项目的更好的解决scheme。

我能想到的最简单的方法就是使用MySQL REGEXP运算符la:

 WHERE foo LIKE '1\D*2\D*3\D*4\D*5' 

这不是特别漂亮,但MySQL没有preg_replace函数,所以我认为这是最好的。

就个人而言,如果这个唯一的数字数据非常重要,我会保留一个单独的字段来包含剥离的数据。 这将使您的查询比正则expression式search快得多。

这篇博客文章详细介绍了如何通过MySQL函数从string中去除非数字字符:

SELECT NumericOnly("asdf11asf");

返回11

http://venerableagents.wordpress.com/2011/01/29/mysql-numeric-functions/

大多数upvoted的答案(@ user1467716)是不是最快的。 充分感谢他们给出一个工作build议,反弹!

这是一个改进版本:

 DELIMITER ;; DROP FUNCTION IF EXISTS `STRIP_NON_DIGIT`;; CREATE DEFINER=`root`@`localhost` FUNCTION `STRIP_NON_DIGIT`(input VARCHAR(255)) RETURNS VARCHAR(255) CHARSET utf8 READS SQL DATA BEGIN DECLARE output VARCHAR(255) DEFAULT ''; DECLARE iterator INT DEFAULT 1; DECLARE lastDigit INT DEFAULT 1; DECLARE len INT; SET len = LENGTH(input) + 1; WHILE iterator < len DO -- skip past all digits SET lastDigit = iterator; WHILE ORD(SUBSTRING(input, iterator, 1)) BETWEEN 48 AND 57 AND iterator < len DO SET iterator = iterator + 1; END WHILE; IF iterator != lastDigit THEN SET output = CONCAT(output, SUBSTRING(input, lastDigit, iterator - lastDigit)); END IF; WHILE ORD(SUBSTRING(input, iterator, 1)) NOT BETWEEN 48 AND 57 AND iterator < len DO SET iterator = iterator + 1; END WHILE; END WHILE; RETURN output; END;; 

在testing服务器上testing5000次:

 -- original Execution Time : 7.389 sec Execution Time : 7.257 sec Execution Time : 7.506 sec -- ORD between not string IN Execution Time : 4.031 sec -- With less substrings Execution Time : 3.243 sec Execution Time : 3.415 sec Execution Time : 2.848 sec 

我也有类似的情况,将产品与条形码匹配,条形码有时不存储任何字母数字,因此在search1022234时需要find数据库中的102.2234。

最后,我只是在产品表中添加了一个新字段reference_number,并且在添加新产品时,php会删除product_number中的非alpha数字来填充reference_number。

您需要对表格执行一次扫描,以便为现有产品创build所有reference_number字段。

然后,您可以设置您的索引,即使速度不是这个操作的一个因素,保持数据库的正常运行仍然是一个好主意,所以这个查询不会妨碍其他查询。

我遇到了这个解决scheme。 user1467716最常见的答案将在phpMyAdmin中有一个小的改变:在代码的末尾添加第二个分隔符。

phpMyAdmin版本是4.1.14; MySQL版本5.6.20

我还加了一个长度限制器

DECLARE count INT DEFAULT 0; 在声明中

AND count < 5WHILE语句中AND count < 5

SET COUNT=COUNT+1;IF声明中

最终forms:

 DROP FUNCTION IF EXISTS STRIP_NON_DIGIT; DELIMITER $$ CREATE FUNCTION STRIP_NON_DIGIT(input VARCHAR(255)) RETURNS VARCHAR(255) BEGIN DECLARE output VARCHAR(255) DEFAULT ''; DECLARE iterator INT DEFAULT 1; DECLARE count INT DEFAULT 0; WHILE iterator < (LENGTH(input) + 1) AND count < 5 DO --limits to 5 chars IF SUBSTRING(input, iterator, 1) IN ( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ) THEN SET output = CONCAT(output, SUBSTRING(input, iterator, 1)); SET COUNT=COUNT+1; END IF; SET iterator = iterator + 1; END WHILE; RETURN output; END $$ DELIMITER $$ --added this 

就我而言,没有正则expression式replace,但是我find了这个解决scheme。

 --Create a table with numbers DROP TABLE IF EXISTS ints; CREATE TABLE ints (i INT UNSIGNED NOT NULL PRIMARY KEY); INSERT INTO ints (i) VALUES ( 1), ( 2), ( 3), ( 4), ( 5), ( 6), ( 7), ( 8), ( 9), (10), (11), (12), (13), (14), (15), (16), (17), (18), (19), (20); --Then extract the numbers from the specified column SELECT bar, GROUP_CONCAT(SUBSTRING(bar, i, 1) ORDER BY i SEPARATOR '') FROM foo JOIN ints ON i BETWEEN 1 AND LENGTH(bar) WHERE SUBSTRING(bar, i, 1) IN ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9') GROUP BY bar; 

它适用于我,我使用MySQL 5.0

我还发现这个地方可以帮助。

用foo表有多大? 如果它很小,速度真的没有关系,你可以拉行ID和foo,使用PHPreplace函数进行比较,然后通过行号拉取所需的信息。

当然,如果桌子太大,这将不会很好。

试试这个例子。 这是用于电话号码,但是你可以修改它的需要。

  -- function removes non numberic characters from input -- returne only the numbers in the string CREATE DEFINER =`root`@`localhost` FUNCTION `remove_alpha`(inputPhoneNumber VARCHAR(50)) RETURNS VARCHAR(50) CHARSET latin1 DETERMINISTIC BEGIN DECLARE inputLenght INT DEFAULT 0; -- var for our iteration DECLARE counter INT DEFAULT 1; -- if null is passed, we still return an tempty string DECLARE sanitizedText VARCHAR(50) DEFAULT ''; -- holder of each character during the iteration DECLARE oneChar VARCHAR(1) DEFAULT ''; -- we'll process only if it is not null. IF NOT ISNULL(inputPhoneNumber) THEN SET inputLenght = LENGTH(inputPhoneNumber); WHILE counter <= inputLenght DO SET oneChar = SUBSTRING(inputPhoneNumber, counter, 1); IF (oneChar REGEXP ('^[0-9]+$')) THEN SET sanitizedText = Concat(sanitizedText, oneChar); END IF; SET counter = counter + 1; END WHILE; END IF; RETURN sanitizedText; END 

使用这个用户定义的函数(UDF)。 假设您有一列电话号码:

 col1 (513)983-3983 1-838-338-9898 phone983-889-8383 

 select remove_alpha(col1) from mytable 

结果是;

 5139833983 18383389898 9838898383