mysql字段中提取汉字,去除数字以及字母

本文介绍了一种在MySQL中提取字段中汉字的方法,并通过数据拆分和正则表达式提高了更新效率,将处理时间从1小时缩短至10分钟内。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求

        最近接到的新需求用户表中有两个字段分别代表用户的系统姓名以及真实姓名,系统姓名在系统中是唯一的用于展示给业务操作人员,减少重名对操作人员的干扰,真实姓名用于用户端展示。但是由于之前需求缺失,并没有对用户真实姓名进行维护,所以这次的要求已系统用户表为准,去掉其中包含的数字以及字母只保留汉字更新到真实姓名中。

这个功能使用只使用一次,不建议使用Java程序处理,因为处理之后还需要重新冗余代码,所以尝试从sql角度,用sql将数据修复。

处理流程

1、提取字段中汉字

2、已提取后为准更新字段

mysql提取汉字主要是按字符循环处理,具体函数如下

DELIMITER $$
DROP FUNCTION IF EXISTS `Num_char`$$
CREATE FUNCTION `Num_char`(Varstring VARCHAR(100)CHARSET utf8) RETURNS VARCHAR(50) CHARSET utf8
BEGIN
	DECLARE len INT DEFAULT 0;
	DECLARE Tmp VARCHAR(100) DEFAULT '';
	SET len=CHAR_LENGTH(Varstring);
		WHILE len > 0 DO
		IF NOT (MID(Varstring,len,1)REGEXP '^[u0391-uFFE5]')
		THEN
		SET Tmp=CONCAT(Tmp,MID(Varstring,len,1));
		END IF;
		SET len = len - 1;
		END WHILE;
	  RETURN REVERSE(Tmp);
    END$$
DELIMITER ;

之后利用Num_char函数直接更新表中字段

注意:mysql中不允许一条sql中表中既有查询又更新,所以把查询做成子表,然后在去更新

UPDATE tb_student student,
( SELECT Num_char ( NAME) studentName, biz_id FROM tb_student WHERE deleted = 0 ) a 
SET student.real_name = a.studentName 
WHERE
	student.biz_id = a.biz_id 
	AND student.deleted =0;

        由于用户表中数据比较大,造成此更新语句特别慢,如果线上执行可能会影响正常业务,所以接下主要是为了提高处理速度。这个更新语句过慢的原因在于Num_char函数,是每条记录中的每个字符都要比较一下,所以造成非常耗时。但是使用sql提取汉字并没有其他的好的方案,只能尝试着从数据上分析,结合业务使用反馈以及数据库数据查看,发现系统名字中函数数字和字母比例不是很高,所以尝试从拆分数据,分开更新,如果只有小部分数据使用Num_char函数,那么速度上也会有很大提高。

更新拆分方案

1、查询系统名字中含有数字和字母的数据,并进行更新,此次利用正则表达式进行配匹

UPDATE tb_student student,
( SELECT Num_char ( `name`) studentName, biz_id FROM tb_student  where name  REGEXP '[0-9|A-Za-z]+') a 
SET student.real_name = a.studentName 
WHERE
	student.biz_id = a.biz_id;

2、将剩余数据的系统名称直接更新到真实姓名上

UPDATE tb_student student,
( SELECT name studentName, biz_id FROM tb_student  where name not REGEXP '[0-9|A-Za-z]+') a 
SET student.real_name = a.studentName 
WHERE
	student.biz_id = a.biz_id;

经过拆分后,时间从1h+已经降到10min以内,处于可以接受范围中了。

题外话

再提供另外一种思路

      以时间为分割线利用临时表将需要处理的字段提前在临时表中处理好,待需求上线后,将临时表和用户表做联合更新,以后利用Num_char函数处理临时表中之外的数据,同样能达到相同的效果。(ps:结合目前系统的表数据量考虑第一种方案处理起来会更简单,大家结合自己的数据合理选择)

总结

        遇到问题解决问题,生活和工作不是考试题目,不是每一个题目都只有一个答案,只要我们愿意去想去做,一定会有更好的方案以及新的惊喜等待我们。各位加油干吧!

ps:mysql字段中根据需要筛选汉字,数字,字符函数如下

DELIMITER $$
DROP FUNCTION IF EXISTS `Num_char_extract`$$
CREATE FUNCTION `Num_char_extract`(Varstring VARCHAR(100)CHARSET utf8, flag INT) RETURNS VARCHAR(50) CHARSET utf8
BEGIN
	DECLARE len INT DEFAULT 0;
	DECLARE Tmp VARCHAR(100) DEFAULT '';
	SET len=CHAR_LENGTH(Varstring);
	IF flag = 0 
	THEN
		WHILE len > 0 DO
		IF MID(Varstring,len,1)REGEXP'[0-9]' THEN
		SET Tmp=CONCAT(Tmp,MID(Varstring,len,1));
		END IF;
		SET len = len - 1;
		END WHILE;
	ELSEIF flag=1
	THEN
		WHILE len > 0 DO
		IF (MID(Varstring,len,1)REGEXP '[a-zA-Z]') 
		THEN
		SET Tmp=CONCAT(Tmp,MID(Varstring,len,1));
		END IF;
		SET len = len - 1;
		END WHILE;
	ELSEIF flag=2
	THEN
		WHILE len > 0 DO
		IF ( (MID(Varstring,len,1)REGEXP'[0-9]')
		OR (MID(Varstring,len,1)REGEXP '[a-zA-Z]') ) 
		THEN
		SET Tmp=CONCAT(Tmp,MID(Varstring,len,1));
		END IF;
		SET len = len - 1;
		END WHILE;
	ELSEIF flag=3
	THEN
		WHILE len > 0 DO
		IF NOT (MID(Varstring,len,1)REGEXP '^[u0391-uFFE5]')
		THEN
		SET Tmp=CONCAT(Tmp,MID(Varstring,len,1));
		END IF;
		SET len = len - 1;
		END WHILE;
	ELSE 
		SET Tmp = 'Error: The second paramter should be in (0,1,2,3)';
		RETURN Tmp;
	END IF;
	RETURN REVERSE(Tmp);
    END$$
DELIMITER ;

使用方式 标识 0 提取数字 1 提取字母 2提取数字+字母 3 提取汉字

select Num_char_extract('字段',标识)

 

<think>我们要从MySQL字段提取数字。假设字段中包含混合内容(字母数字、特殊字符等),我们需要提取中的数字部分。常见的方法有几种:1.使用正则表达式函数(如REGEXP_SUBSTR,但MySQL原生不支持REGEXP_SUBSTR,需要用户自定义函数或使用其他方式)2.使用字符串函数(如SUBSTRING,LOCATE等)组合,但比较复杂。3.创建自定义函数。不过,从MySQL8.0开始,支持REGEXP_SUBSTR函数(注意:在MySQL8.0.0中引入,但可能需要特定版本)。如果你的MySQL版本是8.0及以上,可以使用REGEXP_SUBSTR。如果版本低于8.0,我们可以考虑使用自定义函数。这里提供两种方案:方案一:MySQL8.0及以上使用正则表达式函数我们可以使用REGEXP_SUBSTR来提取第一个连续的数字串。但是注意,如果字段中有多个数字串,我们可能需要提取所有数字串,或者只提取第一个?这里假设我们提取第一个连续的数字串。示例代码:```sqlSELECTREGEXP_SUBSTR(column_name,'[0-9]+')ASnumbersFROMtable_name;```但是,如果字段中没有数字,则返回NULL。如果需要提取所有数字(将非数字部分去掉,将连续的数字合并成一个字符串),可以使用REGEXP_REPLACE(同样需要MySQL8.0+):```sqlSELECTREGEXP_REPLACE(column_name,'[^0-9]','')ASall_numbersFROMtable_name;```注意:这样会把所有数字连在一起,比如'abc123def456'会变成'123456'。方案二:对于不支持正则表达式的MySQL版本(或需要更灵活处理的情况),我们可以创建一个自定义函数。下面是一个自定义函数的例子,用于提取字符串中的第一个连续数字串:```sqlDELIMITER$$CREATEFUNCTIONEXTRACT_NUMBER(inputVARCHAR(255))RETURNSVARCHAR(255)DETERMINISTICBEGINDECLAREoutputVARCHAR(255)DEFAULT'';DECLAREcCHAR(1);DECLAREiINTDEFAULT1;DECLAREinNumberBOOLEANDEFAULTFALSE;IFinputISNULLTHENRETURNNULL;ENDIF;WHILEi<=LENGTH(input)DOSETc=SUBSTRING(input,i,1);IFcBETWEEN'0'AND'9'THENSEToutput=CONCAT(output,c);SETinNumber=TRUE;ELSEIFinNumberTHEN--一旦已经开始匹配数字,然后遇到非数字,就结束(因为我们只取第一个连续数字串)RETURNoutput;ENDIF;ENDIF;SETi=i+1;ENDWHILE;RETURNoutput;END$$DELIMITER;```使用这个函数:```sqlSELECTEXTRACT_NUMBER(column_name)ASnumberFROMtable_name;```这个自定义函数会返回第一个连续的数字串。如果字符串中没有数字,则返回空字符串。但是,如果我们需要提取所有的数字去掉数字字符)并且连在一起,可以修改自定义函数:```sqlDELIMITER$$CREATEFUNCTIONEXTRACT_ALL_NUMBERS(inputVARCHAR(255))RETURNSVARCHAR(255)DETERMINISTICBEGINDECLAREoutputVARCHAR(255)DEFAULT'';DECLAREcCHAR(1);DECLAREiINTDEFAULT1;IFinputISNULLTHENRETURNNULL;ENDIF;WHILEi<=LENGTH(input)DOSETc=SUBSTRING(input,i,1);IFcBETWEEN'0'AND'9'THENSEToutput=CONCAT(output,c);ENDIF;SETi=i+1;ENDWHILE;RETURNoutput;END$$DELIMITER;```使用:```sqlSELECTEXTRACT_ALL_NUMBERS(column_name)ASall_numbersFROMtable_name;```解释:方案一适用于MySQL8.0+,简单高效。方案二适用于低版本,但需要创建函数(需要权限)。注意:自定义函数中,我们使用了循环遍历字符串的每个字符,如果是数字就拼接到结果中。对于只提取第一个连续数字串,我们在遇到非数字且已经进入数字序列时就退出。根据需求选择合适的方法。相关问题:1.如果字段中有多个数字串,如何提取每个数字串(例如,返回第一个、第二个等)?2.如何提取字段中的字母部分?3.在MySQL中,如何使用正则表达式替换字符串中的数字字符?4.如果数字串包含小数点(即提取浮点数),该如何修改?</think>### 在 MySQL提取字段中的数字MySQL提取字段中的数字,常见场景包括: 1. **提取数字串**(如 `abc123def` → `123`) 2. **提取所有数字字符**(如 `a1b2c3` → `123`) 3. **提取浮点数**(如 `price: $12.34` → `12.34`) 以下是三种常用方法(根据 MySQL 版本选择): --- #### 方法 1:使用正则表达式(MySQL 8.0+) MySQL 8.0+ 原生支持 `REGEXP_SUBSTR()`,适合提取连续数字串: ```sql -- 提取第一个连续数字串(如 "abc123def456" → "123") SELECT REGEXP_SUBSTR(your_column, '[0-9]+') AS extracted_number FROM your_table; -- 提取所有数字字符(如 "a1b2c3" → "123") SELECT REGEXP_REPLACE(your_column, '[^0-9]', '') AS all_digits FROM your_table; ``` #### 方法 2:自定义函数(任何 MySQL 版本) 创建函数提取连续数字串(支持浮点数): ```sql DELIMITER $$ CREATE FUNCTION EXTRACT_NUMBER(input VARCHAR(255)) RETURNS VARCHAR(255) DETERMINISTIC BEGIN DECLARE output VARCHAR(255) DEFAULT ''; DECLARE i INT DEFAULT 1; DECLARE decimal_found BOOLEAN DEFAULT FALSE; WHILE i <= LENGTH(input) DO SET @char = SUBSTRING(input, i, 1); -- 匹配数字或小数点(仅允许第一个小数点) IF (@char BETWEEN '0' AND '9') OR (@char = '.' AND NOT decimal_found) THEN SET output = CONCAT(output, @char); IF @char = '.' THEN SET decimal_found = TRUE; END IF; -- 遇到非数字且已有数字时终止 ELSEIF output != '' THEN LEAVE loop_label; END IF; SET i = i + 1; END WHILE loop_label; RETURN output; END$$ DELIMITER ; -- 使用示例 SELECT EXTRACT_NUMBER('price: $12.34') AS result; -- 返回 '12.34' ``` #### 方法 3:纯字符串操作(兼容低版本) 使用嵌套 `REPLACE` 移除非数字字符: ```sql -- 移除非数字字符(保留数字) SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( your_column, 'a', ''), 'b', ''), 'c', ''), 'd', ''), 'e', ''), 'f', ''), 'g', ''), 'h', ''), 'i', ''), 'j', '') AS digits FROM your_table; -- 注意:需扩展替换所有字母(此方法不推荐,仅作演示) ``` --- ### 关键解释 1. **正则表达式方法**: - `[0-9]+`:匹配连续数字 - `[^0-9]`:匹配非数字字符(`REGEXP_REPLACE` 中用于删除) - **优点**:简洁高效;**缺点**:仅限 MySQL 8.0+ 2. **自定义函数**: - 逐字符扫描,识别数字和小数点 - `decimal_found` 确保只保留一个小数点 - **优点**:兼容所有版本,支持浮点数;**缺点**:需创建函数 3. **应用场景建议**: - 简单需求 → 正则表达式(MySQL 8.0+) - 兼容低版本/复杂需求 → 自定义函数 - 浮点数提取 → 自定义函数(正则需调整) --- ### 示例测试数据 ```sql CREATE TABLE test_data ( id INT, mixed_text VARCHAR(255) ); INSERT INTO test_data VALUES (1, 'abc123def'), (2, 'price: $45.67'), (3, 'ID-789XYZ'); -- 使用自定义函数查询 SELECT mixed_text, EXTRACT_NUMBER(mixed_text) AS extracted FROM test_data; ``` **结果**: | mixed_text | extracted | |-----------------|-----------| | abc123def | 123 | | price: $45.67 | 45.67 | | ID-789XYZ | 789 | ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mandy_i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值