我希望在表格中找到与用户输入的特定号码相匹配的记录。因此,用户可以输入12345,但这可能是数据库中的123zz4-5。
如果PHP函数在MySQL中有效,我想像这样的东西会起作用。
SELECT * FROM foo WHERE preg_replace("/[^0-9]/","",bar) = '12345'
只用MySQL做同样的功能或方法是什么?
答案 0 :(得分:37)
我意识到这是一个古老的话题,但谷歌搜索这个问题我找不到一个简单的解决方案(我看到了古老的代理人,但认为这是一个更简单的解决方案)所以这是我写的一个函数,似乎工作得很好
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
$$
答案 1 :(得分:7)
虽然它不漂亮且显示的结果不匹配,但这有助于:
SELECT * FROM foo WHERE bar LIKE = '%1%2%3%4%5%'
我仍然希望找到一个类似于原始问题项目的更好的解决方案。
答案 2 :(得分:7)
没有regexp替换,只有一个普通的字符串REPLACE()。
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]*';
这就像你的LIKE版本,但更准确地匹配。两者都表现同样糟糕,需要没有索引的全表扫描。
答案 3 :(得分:6)
最受欢迎的答案(@ user1467716)并不是最快的。对他们给予工作建议反弹的全部赞誉!
这是一个改进的版本:
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;;
在测试服务器上测试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
答案 4 :(得分:3)
我能想到的最简单的方法是使用MySQL REGEXP运算符la:
WHERE foo LIKE '1\D*2\D*3\D*4\D*5'
它并不是特别漂亮,但MySQL没有preg_replace
功能,所以我认为这是你最好的。
就个人而言,如果这个唯一的数字数据如此重要,我会保留一个单独的字段来包含剥离的数据。它会使您的查找速度比使用正则表达式搜索快得多。
答案 5 :(得分:3)
此博客文章详细介绍了如何通过MySQL函数从字符串中删除非数字字符:
SELECT NumericOnly("asdf11asf");
返回11
http://venerableagents.wordpress.com/2011/01/29/mysql-numeric-functions/
答案 6 :(得分:3)
您可以使用REGEXP_REPLACE
轻松做到您想要的(与MySQL 8+和MariaDB 10.0.5 +兼容)
REGEXP_REPLACE(expr, pat, repl[, pos[, occurrence[, match_type]]])
将字符串expr中与模式pat指定的正则表达式匹配的匹配项替换为替换字符串repl,并返回结果字符串。如果expr,pat或repl为NULL,则返回值为NULL。
试一试:
SELECT REGEXP_REPLACE('123asd12333', '[a-zA-Z]+', '');
<强>输出:强>
12312333
答案 7 :(得分:1)
我有类似的情况,将产品与条形码匹配,条形码有时不会存储任何字母数字,因此在搜索1022234时需要找到数据库中的102.2234。
最后,我刚刚在products表中添加了一个新字段reference_number,并且每当添加新产品时,php都会删除product_number中的无alpha数字以填充reference_number。
您需要对表进行一次扫描,以便为现有产品创建所有reference_number字段。
然后您可以设置索引,即使速度不是此操作的一个因素,保持数据库运行良好仍然是一个好主意,因此此查询不会使其陷入困境并减慢其他查询。
答案 8 :(得分:1)
我遇到了这个解决方案。 user1467716的最佳答案将在phpMyAdmin中进行一些小改动:在代码末尾添加第二个分隔符标记。
phpMyAdmin版本是4.1.14; MySQL版本5.6.20
我还使用
添加了长度限制器 声明中的 DECLARE count INT DEFAULT 0;
AND count < 5
声明中的 WHILE
SET COUNT=COUNT+1;
声明
IF
最终形式:
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
答案 9 :(得分:0)
就我而言,没有正则表达式取代,但我找到了这个解决方案;
--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
此外,我发现此place可能有所帮助。
答案 10 :(得分:0)
foo的桌子有多大?如果它很小,并且速度确实无关紧要,你可以拉出行ID和foo,使用PHP替换函数进行循环比较,然后按行号拉出你想要的信息。
当然,如果桌子太大,这将无法正常工作。
答案 11 :(得分:0)
试试这个例子。这用于电话号码,但您可以根据需要进行修改。
-- 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
答案 12 :(得分:0)
自从我从这里开始构建函数以来,我想分享一下。我只是重新排列了一下,以便于阅读(我只是服务器端)。
您可以通过传入表名和列名来调用它,以使其删除该列中所有现有的非数字字符。我继承了很多错误的表结构,这些结构将大量的int字段作为varchar放置,因此需要一种方法来快速清理这些字段,然后才能将列修改为整数。
drop procedure if exists strip_non_numeric_characters;
DELIMITER ;;
CREATE PROCEDURE `strip_non_numeric_characters`(
tablename varchar(100)
,columnname varchar(100)
)
BEGIN
-- =============================================
-- Author: <Author,,David Melton>
-- Create date: <Create Date,,2/26/2019>
-- Description: <Description,,loops through data and strips out the bad characters in whatever table and column you pass it>
-- =============================================
#this idea was generated from the idea STRIP_NON_DIGIT function
#https://stackoverflow.com/questions/287105/mysql-strip-non-numeric-characters-to-compare
declare input,output varchar(255);
declare iterator,lastDigit,len,counter int;
declare date_updated varchar(100);
select column_name
into date_updated
from information_schema.columns
where table_schema = database()
and extra rlike 'on update CURRENT_TIMESTAMP'
and table_name = tablename
limit 1;
#only goes up to 255 so people don't run this for a longtext field
#just to be careful, i've excluded columns that are part of keys, that could potentially mess something else up
set @find_column_length =
concat("select character_maximum_length
into @len
from information_schema.columns
where table_schema = '",database(),"'
and column_name = '",columnname,"'
and table_name = '",tablename,"'
and length(ifnull(character_maximum_length,100)) < 255
and data_type in ('char','varchar')
and column_key = '';");
prepare stmt from @find_column_length;
execute stmt;
deallocate prepare stmt;
set counter = 1;
set len = @len;
while counter <= ifnull(len,1) DO
#this just removes it by putting all the characters before and after the character i'm looking at
#you have to start at the end of the field otherwise the lengths don't stay in order and you have to run it multiple times
set @update_query =
concat("update `",tablename,"`
set `",columnname,"` = concat(substring(`",columnname,"`,1,",len - counter,"),SUBSTRING(`",columnname,"`,",len - counter,",",counter - 1,"))
",if(date_updated is not null,concat(",`",date_updated,"` = `",date_updated,"`
"),''),
"where SUBSTRING(`",columnname,"`,",len - counter,", 1) not REGEXP '^[0-9]+$';");
prepare stmt from @update_query;
execute stmt;
deallocate prepare stmt;
set counter = counter + 1;
end while;
END ;;
DELIMITER ;
答案 13 :(得分:0)
要搜索与字符串中的特定数字模式匹配的数字,请按照以下类似方式首先删除所有字母和特殊字符,然后将值转换为整数,然后搜索
SELECT *
FROM foo
WHERE Convert(Regexp_replace(bar, '[a-zA-Z]+', ''), signed) = 12345
答案 14 :(得分:-1)
在MySQL 8.0+上,有一个新的本机函数,称为REGEXP_REPLACE。一个解决该问题的方法是:
SELECT * FROM foo WHERE REGEXP_REPLACE(bar,'[^0-9]+',"") = '12345'