mysql如何将值中最后两位修改为*号

本文介绍了一种在数据库中对身份证号码进行脱敏处理的方法,通过SQL语句将身份证号的最后两位替换为**,以保护个人隐私。

    业务需要,将表中身份证字符的最后两位修改为**,测试后如下sql无误:

         update  TABLE_NAME  set  idcard=CONCAT(left(idcard,CHAR_LENGTH(idcard)-2),'**')

<think>我们有一个字符串,需要将第4位到第10位(包括)的字符替换为星*)。注意:在SQL中,字符串索引通常从1开始。 我们可以使用以下步骤: 1. 截取字符串的前3个字符(位置1到3)。 2. 生成7个星(因为从位置4到10一共7个字符)。 3. 截取字符串从第11位开始到末尾的部分。 4. 将这三部分连接起来。 但是,需要注意的是,字符串可能不足10个字符。如果字符串长度小于4,则不需要替换;如果字符串长度在4到10之间,则替换从第4位到字符串末尾,用星替换直到第10位(但实际可能不到10位,所以需要按实际长度替换)。 因此,我们可以这样处理: 使用LEFT函数取前3个字符,然后使用一个由星组成的字符串(长度为从第4位到第10位的长度,但最多7个,如果不足则按实际长度),然后再加上剩下的部分(从第11位开始)。 但是,更通用的方法是: 我们可以使用: CONCAT( LEFT(str, 3), REPEAT('*', GREATEST(0, LEAST(7, LENGTH(str) - 3))), SUBSTRING(str, 11) ) 解释: - LEFT(str,3):取前3个字符。 - 然后我们要生成一个星字符串,长度应该是从第4位到第10位,但要注意字符串可能不够长。 如果字符串长度小于4,那么不需要替换,所以星长度为0。 如果字符串长度在4到10之间,那么星长度为 (字符串长度-3) (因为从第4位到字符串末尾)。 如果字符串长度大于10,那么星长度为7(因为4到10共7个位置)。 所以我们可以用:LEAST(7, LENGTH(str)-3) 来得到需要替换的星数量(但注意如果LENGTH(str)-3是负数,则取0)。所以用GREATEST(0, ...)确保非负。 - 最后,如果字符串长度大于10,则加上从第11位开始的子串;如果小于等于10,则加上空字符串。 但是,注意:SUBSTRING(str, 11) 在str长度小于11时返回空字符串,所以可以直接使用。 因此,完整的表达式为: CONCAT( LEFT(str, 3), REPEAT('*', GREATEST(0, LEAST(7, LENGTH(str) - 3))), SUBSTRING(str, 11) ) 但是,我们也可以使用CASE语句来处理,但上述方法可以避免使用CASE。 然而,还有一种更简洁的方式:使用INSERT函数。INSERT函数可以替换字符串的一部分。 语法:INSERT(str, pos, len, newstr) 这里,pos是开始替换的位置(从1开始),len是要替换的长度,newstr是替换的字符串。 所以我们可以这样写: INSERT(str, 4, 7, REPEAT('*', LEAST(7, LENGTH(str)-3))) 但是,注意:如果字符串长度小于4,则不会替换(因为从位置4开始,所以不会影响)。如果字符串长度在4到10之间,那么LEAST(7, LENGTH(str)-3)会得到实际要替换的长度(即从位置4到末尾的长度),然后替换成相同长度的星。如果字符串长度大于10,则替换7个字符。 因此,使用INSERT函数更简单。 但是,当替换的长度为0时,INSERT函数会怎样?如果len=0,则相当于在pos位置插入newstr,但我们希望的是替换0个字符(即不替换)?实际上,我们不需要替换0个字符,因为当字符串长度小于4时,LEAST(7, LENGTH(str)-3)会为负数?所以我们需要确保替换长度非负。 修正:使用GREATEST(0, LENGTH(str)-3) 来避免负数,然后LEAST(7, ...) 取最小。 但是,在INSERT函数中,如果len为0,则不会删除任何字符,而是插入星字符串(长度为0的字符串),所以不会有问题。 因此,我们可以这样写: INSERT(str, 4, GREATEST(0, LEAST(7, LENGTH(str)-3)), REPEAT('*', GREATEST(0, LEAST(7, LENGTH(str)-3)))) 注意:替换的长度和星的长度必须一致。所以我们可以用一个变量表示长度,但在SQL中不能直接使用变量(除非在存储过程中),所以需要重复计算。 为了简化,我们可以这样写: INSERT(str, 4, CASE WHEN LENGTH(str) < 4 THEN 0 WHEN LENGTH(str) < 11 THEN LENGTH(str)-3 ELSE 7 END, REPEAT('*', CASE WHEN LENGTH(str) < 4 THEN 0 WHEN LENGTH(str) < 11 THEN LENGTH(str)-3 ELSE 7 END)) 这样更清晰,但有点冗长。 我们也可以使用一个中间表达式(使用用户变量)来避免重复,但在一般的SQL语句中,我们可能不能使用变量。 因此,我们可以选择第一种方法(使用CONCAT)或者使用INSERT函数配合CASE。 考虑到可读性,使用CONCAT的方法可能更直观: SELECT CONCAT( LEFT(str, 3), REPEAT('*', CASE WHEN LENGTH(str) < 4 THEN 0 WHEN LENGTH(str) < 11 THEN LENGTH(str)-3 ELSE 7 END), SUBSTRING(str, 11) ) AS masked_str 或者,使用INSERT函数: SELECT INSERT(str, 4, CASE WHEN LENGTH(str) < 4 THEN 0 WHEN LENGTH(str) < 11 THEN LENGTH(str)-3 ELSE 7 END, REPEAT('*', CASE WHEN LENGTH(str) < 4 THEN 0 WHEN LENGTH(str) < 11 THEN LENGTH(str)-3 ELSE 7 END) ) AS masked_str 两种方法都可以。 我们也可以不用CASE,用数学表达式,但CASE更清晰。 下面我们提供一个使用CASE的示例。 但是,我们也可以不用CASE,而用GREATEST和LEAST,但需要一点技巧: 替换的长度 = GREATEST(0, LEAST(7, LENGTH(str)-3)) 然后星的个数也是这个。 所以可以写成: SELECT INSERT(str, 4, GREATEST(0, LEAST(7, LENGTH(str)-3)), REPEAT('*', GREATEST(0, LEAST(7, LENGTH(str)-3))) ) AS masked_str 这个表达式可以处理所有情况: - 如果LENGTH(str) <= 3,则LENGTH(str)-3 <=0,所以GREATEST(0, ...) 为0,即替换0个字符,替换成0个星(相当于没变)。 - 如果LENGTH(str)在4到10之间,则LEAST(7, LENGTH(str)-3) 等于 LENGTH(str)-3(因为小于7),所以替换长度为LENGTH(str)-3,星个数也是这个数。 - 如果LENGTH(str)>=11,则LEAST(7, LENGTH(str)-3)等于7,所以替换7个字符,用7个星。 因此,这个表达式更简洁。 所以,最终的SQL语句可以这样写: UPDATE 表名 SET 列名 = INSERT(列名, 4, GREATEST(0, LEAST(7, LENGTH(列名)-3)), REPEAT('*', GREATEST(0, LEAST(7, LENGTH(列名)-3)))) WHERE ...; -- 如果需要条件 或者查询时: SELECT INSERT(列名, 4, GREATEST(0, LEAST(7, LENGTH(列名)-3)), REPEAT('*', GREATEST(0, LEAST(7, LENGTH(列名)-3)))) AS masked_value FROM 表名; 注意:如果字符串中从第4位到第10位包含多字节字符(如UTF-8),那么上述函数可能不会按预期工作,因为LENGTH函数在MySQL中默认返回字节数,而不是字符数。如果使用多字节字符集,应该使用CHAR_LENGTH函数(返回字符数)和SUBSTR函数(按字符操作)。 因此,如果字符串是UTF-8等多字节字符集,我们需要用CHAR_LENGTH代替LENGTH,用SUBSTRING(列名, 1, 3)(按字符)来取前3个字符?但是,在INSERT函数中,位置和长度也是按字符还是字节?在MySQL中,INSERT函数是按字符的(如果使用多字节安全字符集),因为它是字符串函数,会考虑字符集。 但是,为了安全起见,我们假设字符串是单字节的(如latin1)或者只包含单字节字符(如ASCII)。如果字符串包含多字节字符,那么位置4可能不是第4个字符(可能是第4个字节,而一个字符可能占多个字节)。所以,如果字符串包含多字节字符,我们需要确保按字符处理。 在MySQL中,INSERT(str, pos, len, newstr)函数中的pos和len参数是按字符的,所以它支持多字节字符。因此,我们不需要做额外处理。 但是,我们使用LENGTH函数时,如果按字节计算,那么对于多字节字符,LENGTH(str)返回的是字节数,而我们需要的是字符数。所以,应该使用CHAR_LENGTH(str)来获取字符数。 因此,修正为: SELECT INSERT(str, 4, GREATEST(0, LEAST(7, CHAR_LENGTH(str)-3)), REPEAT('*', GREATEST(0, LEAST(7, CHAR_LENGTH(str)-3))) ) AS masked_str 这样,无论字符串是单字节还是多字节字符,都能正确处理。 所以,最终答案:使用INSERT函数,结合CHAR_LENGTH函数(如果字符串可能包含多字节字符)或LENGTH函数(如果确定是单字节字符)。 示例: 假设str='1234567890ABCD', 则替换后为:123*******BCD (因为第4到10位替换为7个星,然后加上剩余部分) 但实际上,替换后:前3个字符是'123',然后替换7个字符(从第4到10)为7个星,然后从第11位开始取,即'BCD',所以结果为'123*******BCD' 如果str='123456',则替换后:前3个字符'123',然后替换3个字符(因为CHAR_LENGTH(str)-3=3,小于7)为3个星,然后从第11位取(没有字符)所以结果为'123***' 如果str='12',则替换长度为0,所以结果还是'12' 注意:如果字符串长度正好为10,则替换后为:前3个字符+7个星,然后从第11位开始为空,所以结果为'123*******' 因此,符合要求。 总结:使用以下表达式: INSERT(str, 4, GREATEST(0, LEAST(7, CHAR_LENGTH(str) - 3)), REPEAT('*', GREATEST(0, LEAST(7, CHAR_LENGTH(str) - 3))) ) 或者,为了避免重复计算,可以使用变量(在存储过程中)或者使用派生表,但在普通SQL中,重复计算两次是允许的。 所以,在查询或更新中直接使用即可。</think>在 MySQL 中,将字符串从第 4 位到第 10 位替换为星*)可以通过 `INSERT()` 和 `REPEAT()` 函数组合实现。以下是完整解决方案: ### 解决方案 ```sql SELECT INSERT( your_column, -- 替换目标列 4, -- 起始位置(从第4位开始) GREATEST(0, LEAST(7, CHAR_LENGTH(your_column) - 3)), -- 计算替换长度 REPEAT('*', GREATEST(0, LEAST(7, CHAR_LENGTH(your_column) - 3))) -- 生成星字符串 ) AS masked_string FROM your_table; ``` ### 关键函数说明 1. **`CHAR_LENGTH(your_column)`** 获取字符串的**字符长度**(支持多字节字符如中文) 2. **`GREATEST(0, LEAST(7, N))`** - 动态计算替换长度(确保在 0-7 范围内) - `N = CHAR_LENGTH(your_column) - 3`(从第4位到末尾的长度) - 处理边界情况: - 字符串长度 ≤ 3 时:替换长度为 0(不修改) - 长度在 4-10 时:替换实际长度(如长度8则替换5个字符) - 长度 ≥ 11 时:固定替换7个字符 3. **`REPEAT('*', N)`** 生成指定数量(N)的星字符串 4. **`INSERT(str, pos, len, newstr)`** - `str`: 原始字符串 - `pos`: 替换起始位置(从1开始计数) - `len`: 要替换的字符数 - `newstr`: 替换的新字符串 ### 示例效果 | 原始字符串 | 替换后结果 | 说明 | |--------------------|-------------------|-------------------------------| | `'1234567890ABCD'` | `'123*******BCD'` | 长度>10,替换7位(第4-10位) | | `'1234567'` | `'123****'` | 长度=7,替换4位(第4-7位) | | `'你好ABC世界'` | `'你好***世界'` | 中文支持(替换第3-5个字符) | | `'abc'` | `'abc'` | 长度<4,不替换 | ### 重要说明 1. **位置计算规则** MySQL 字符串位置从 **1 开始计数**(非0),且函数按**字符**处理(非字节),支持多语言字符。 2. **更新数据写法** 若需永久修改数据,使用 `UPDATE`: ```sql UPDATE your_table SET your_column = INSERT(your_column, 4, GREATEST(0, LEAST(7, CHAR_LENGTH(your_column) - 3)), REPEAT('*', GREATEST(0, LEAST(7, CHAR_LENGTH(your_column) - 3))) ); ``` 3. **性能建议** 对超长文本(如 `TEXT` 类型),先用 `SUBSTRING()` 截取处理部分内容,避免全文本操作。 ### 替代方案(正则表达式) MySQL 8.0+ 支持 `REGEXP_REPLACE`: ```sql SELECT REGEXP_REPLACE( your_column, '^(.{3}).{1,7}', CONCAT('$1', REPEAT('*', GREATEST(0, LEAST(7, CHAR_LENGTH(your_column)-3)))) ) AS masked_string FROM your_table; ``` > ⚠️ 此方法在短字符串时需额外处理边界条件
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值