MySQL MySQL剥离非数字字符进行比较

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/287105/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 12:23:13  来源:igfitidea点击:

MySQL strip non-numeric characters to compare

mysqlregex

提问by Chris Bartow

I'm looking to find records in a table that match a specific number that the user enters. So, the user may enter 12345, but this could be 123zz4-5 in the database.

我希望在表中查找与用户输入的特定数字相匹配的记录。因此,用户可能会输入 12345,但这可能是数据库中的 123zz4-5。

I imagine something like this would work, if PHP functions worked in MySQL.

如果 PHP 函数在 MySQL 中工作,我想这样的事情会起作用。

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

What's the equivalent function or way to do this with just MySQL?

仅使用 MySQL 执行此操作的等效功能或方法是什么?

采纳答案by Chris Bartow

While it's not pretty and it shows results that don't match, this helps:

虽然它不漂亮并且显示的结果不匹配,但这有助于:

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

I would still like to find a better solution similar to the item in the original question.

我仍然想找到一个更好的解决方案,类似于原始问题中的项目。

回答by user1467716

I realise that this is an ancient topic but upon googling this problem I couldn't find a simple solution (I saw the venerable agents but think this is a simpler solution) so here's a function I wrote, seems to work quite well.

我意识到这是一个古老的话题,但是在谷歌搜索这个问题时我找不到一个简单的解决方案(我看到了古老的代理,但认为这是一个更简单的解决方案)所以这是我写的一个函数,似乎工作得很好。

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
$$

回答by wally

Most upvoted answer aboveisn't the fastest.
Full kudos to them for giving a working proposal to bounce off!

上面最受好评的答案并不是最快的。
非常感谢他们提出了一个可行的建议来反弹!

This is an improved version:

这是一个改进版本:

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 5000 times on a test server:

在测试服务器上测试 5000 次:

-- 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

回答by Marlom

You can easily do what you want with REGEXP_REPLACE(compatible with MySQL 8+ and MariaDB 10.0.5+)

您可以轻松地做您想做的事REGEXP_REPLACE(兼容 MySQL 8+ 和 MariaDB 10.0.5+)

REGEXP_REPLACE(expr, pat, repl[, pos[, occurrence[, match_type]]])

Replaces occurrences in the string expr that match the regular expression specified by the pattern pat with the replacement string repl, and returns the resulting string. If expr, pat, or repl is NULL, the return value is NULL.

Go to REGEXP_REPLACE doc: MySQLor MariaDB

REGEXP_REPLACE(expr, pat, repl[, pos[, occurrence[, match_type]]])

用替换字符串 repl 替换字符串 expr 中与模式 pat 指定的正则表达式匹配的匹配项,并返回结果字符串。如果 expr、pat 或 repl 为 NULL,则返回值为 NULL。

转到 REGEXP_REPLACE 文档:MySQLMariaDB

Try it:

尝试一下:

SELECT REGEXP_REPLACE('123asd12333', '[a-zA-Z]+', '');

Output:

输出:

12312333

回答by bobince

There's no regexp replace, only a plain string REPLACE().

没有正则表达式替换,只有一个普通字符串 REPLACE()。

MySQL has the REGEXP operator, but it's only a match tester not a replacer, so you would have to turn the logic inside-out:

MySQL 有 REGEXP 运算符,但它只是一个匹配测试器而不是替换器,因此您必须将逻辑翻转过来:

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

This is like your version with LIKE but matches more accurately. Both will perform equally badly, needing a full table scan without indexes.

这就像你的 LIKE 版本,但匹配得更准确。两者的性能都一样差,需要无索引的全表扫描。

回答by Gareth

The simplest way I can think to do it is to use the MySQL REGEXP operator a la:

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

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

It's not especially pretty but MySQL doesn't have a preg_replacefunction so I think it's the best you're going to get.

它不是特别漂亮,但 MySQL 没有preg_replace功能,所以我认为它是你将要得到的最好的。

Personally, if this only-numeric data is so important, I'd keep a separate field just to contain the stripped data. It'll make your lookups a lot faster than with the regular expression search.

就个人而言,如果这个只有数字的数据如此重要,我会保留一个单独的字段来包含剥离的数据。它将使您的查找比使用正则表达式搜索快得多。

回答by Jeremy Warne

This blog post details how to strip non-numeric characters from a string via a MySQL function:

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

SELECT NumericOnly("asdf11asf");

SELECT NumericOnly("asdf11asf");

returns 11

返回 11

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

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

回答by user396149

I have a similar situation, matching products to barcodes where the barcode doesn't store none alpha numerics sometimes, so 102.2234 in the DB needs to be found when searching for 1022234.

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

In the end I just added a new field, reference_number to the products tables, and have php strip out the none alpha numerics in the product_number to populate reference_number whenever a new products is added.

最后,我只是在产品表中添加了一个新字段 reference_number,并让 php 去掉 product_number 中的无字母数字,以便在添加新产品时填充 reference_number。

You'd need to do a one time scan of the table to create all the reference_number fields for existing products.

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

You can then setup your index, even if speed is not a factor for this operation, it is still a good idea to keep the database running well so this query doesn't bog it down and slow down other queries.

然后您可以设置您的索引,即使速度不是这个操作的一个因素,保持数据库运行良好仍然是一个好主意,这样这个查询就不会陷入困境并减慢其他查询的速度。

回答by modle13

I came across this solution. The top answer by user1467716 will work in phpMyAdmin with a small change: add a second delimiter tag to the end of the code.

我遇到了这个解决方案。user1467716 的最佳答案将在 phpMyAdmin 中工作,只需稍作更改:在代码末尾添加第二个分隔符标记。

phpMyAdmin version is 4.1.14; MySQL version 5.6.20

phpMyAdmin 版本为 4.1.14;MySQL 版本 5.6.20

I also added a length limiter using

我还使用添加了一个长度限制器

DECLARE count INT DEFAULT 0;in the declarations

DECLARE count INT DEFAULT 0;在声明中

AND count < 5in the WHILEstatement

AND count < 5WHILE声明中

SET COUNT=COUNT+1;in the IFstatement

SET COUNT=COUNT+1;IF声明中

Final form:

最终形式:

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

回答by Nelson Miranda

There's no regex replace as far as I'm concerned, but I found this solution;

就我而言,没有正则表达式替换,但我找到了这个解决方案;

--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;

It works for me and I use MySQL 5.0

它对我有用,我使用 MySQL 5.0

Also I found this placethat could help.

我也发现这个地方可以提供帮助。