MySQL按照按照某字段截取部分值后GROUP BY

本文介绍了一种使用SQL中的substr函数从特定格式的时间戳中提取年份的方法,并通过一个具体的例子展示了如何根据年份对数据进行分组统计。

可能用到的场景:

消费表:

有时间字段201611201230是年月日时分,但是统计是可能要按照年或者月来查询,那就可以使用substr来完成

SELECT SUM(a.ss) FROM(
SELECT substr(TALLY_TIME,1,4) tt,AMOUNT_PAID ss,FIRST_CLASSIFY_NAME FROM tally) a 
GROUP BY a.tt

这样就可以截取时间到年.从而算出每一年的统计数据

转载于:https://my.oschina.net/MrBamboo/blog/787755

<think>好的,用户现在想用MySQL的REGEXP_SUBSTR函数来提取字段中的所有数字。之前他问过如何提取非数字,现在反过来要数字了。我需要仔细分析他的需求,并结合之前的回答和提供的参考资料来给出解决方案。 首先,回顾之前的回答,用户已经了解如何使用REGEXP_SUBSTR配合递归CTE来提取所有非数字字符。现在需要类似的思路,但目标换成数字。核心的正则表达式需要从匹配非数字改成匹配数字,也就是将[^0-9]+改为[0-9]+。不过要注意,用户这次是要提取所有数字,而不仅仅是第一个匹配项。 用户提供的参考资料中,引用[1]详细说明了REGEXP_SUBSTR的基本用法,引用[2]和[3]提到了使用递归CTE或CONNECT BY LEVEL的方法来拆分字符串,这可能适用于提取多个匹配项。但MySQL不支持CONNECT BY,所以需要继续使用递归CTE的方法,就像之前处理非数字那样。 接下来需要确定如何调整正则表达式。原来的正则表达式是[^0-9]+,现在应该是[0-9]+,用来匹配一个或多个连续的数字。同时,用户可能需要将所有匹配的数字连接起来,形成完整的数字字符串。 在之前的回答中,递归CTE通过不断增加occurrence参数来遍历所有匹配的非数字片段。同样的方法可以应用在这里,只是正则表达式改为匹配数字。此外,用户可能需要处理字符串中的多个数字片段,例如“A12B34C56”中的12、34、56,需要将它们提取并合并为123456或者保留原样,这需要根据用户需求调整。如果用户希望保留每个数字片段的顺序,合并的话就需要用GROUP_CONCAT,否则可能需要单独列出每个数字部分。 需要注意的是,递归CTE在MySQL中的限制,尤其是处理长字符串时可能会有性能问题。需要提醒用户这一点,并提供优化建议,比如预过滤或限制匹配长度。 另外,用户可能混淆了REGEXP_SUBSTR和REGEXP_REPLACE的功能。例如,直接替换非数字字符可能更简单,但用户明确要求使用REGEXP_SUBSTR,所以需要坚持用该函数的方法。但也可以提供替代方案,比如用REGEXP_REPLACE删除非数字字符,这样更高效,但可能不符合用户的具体需求。 还要考虑特殊场景,比如字符串中没有数字的情况,或者数字之间有其他字符分隔的情况。例如,在示例中的“Ab12#c%78”提取数字应该得到“1278”还是“12”和“78”?根据用户的问题描述,“截取字段中的所有数字”,可能是指提取所有数字字符并合并,因此需要用递归CTE提取每个数字段再连接。 最后,确保回答结构清晰,分步骤说明,包括正则表达式设计、递归CTE方法、参数说明、示例以及优化建议。同时,生成的相关问题需要与当前主题相关,比如性能优化、替代方法等。</think>以下是在 MySQL 中提取所有数字的完整解决方案: ### 一、核心正则表达式设计 $$ [0-9]+ $$ - **`[0-9]`**:匹配所有数字字符(等价于 $\\d$) - **`+`**:连续匹配 1 次或多次 ### 二、递归 CTE 提取全部数字 ```sql WITH RECURSIVE num_extract AS ( SELECT 'A1B23CD456' AS origin_str, REGEXP_SUBSTR('A1B23CD456', '[0-9]+', 1, 1) AS num_part, 1 AS occurrence UNION ALL SELECT origin_str, REGEXP_SUBSTR(origin_str, '[0-9]+', 1, occurrence + 1), occurrence + 1 FROM num_extract WHERE REGEXP_SUBSTR(origin_str, '[0-9]+', 1, occurrence + 1) IS NOT NULL ) SELECT GROUP_CONCAT(num_part SEPARATOR '') AS all_numbers FROM num_extract WHERE num_part IS NOT NULL; -- 返回 '123456' [^1] ``` ### 三、关键参数说明 | 参数 | 作用 | 示例 | |------|------|------| | `position=2` | 从第 2 个字符开始搜索 | `REGEXP_SUBSTR('X1Y2Z3', '[0-9]+', 2)` → `'2'` | | `occurrence=3` | 获取第 3 个匹配项 | `REGEXP_SUBSTR('A1B2C3D4', '[0-9]+', 1, 3)` → `'3'` | | `match_type='i'` | 对字母部分忽略大小写 | `REGEXP_SUBSTR('a1B2c3', '[0-9]+', 1, 1, 'i')` → `'1'` | ### 四、特殊场景处理 #### 1. 合并分散的数字 输入:`'Ab12#c%78'` → 输出:`'1278` ```sql -- 使用上述递归 CTE 的 GROUP_CONCAT 方案 ``` #### 2. 保留数字分隔符 输入:`'1-800-555-1234'` → 输出:`['1','800','555','1234']` ```sql SELECT REGEXP_SUBSTR(phone_number, '[0-9]+', 1, level) FROM dual CONNECT BY LEVEL <= REGEXP_COUNT(phone_number, '[0-9]+'); -- 需改用 MySQL 的递归 CTE 实现 [^2] ``` ### 五、性能优化方案 1. **预过滤加速**: ```sql WHERE col REGEXP '[0-9]' -- 先过滤含数字的记录 ``` 2. **限制匹配长度**: ```sql [0-9]{1,10} -- 最多匹配 10 位连续数字 ``` 3. **虚拟列缓存**: ```sql ALTER TABLE orders ADD COLUMN numeric_part VARCHAR(20) GENERATED ALWAYS AS (REGEXP_REPLACE(order_code, '[^0-9]', '')); ``` ### 六、替代方案对比 | 方法 | 优点 | 缺点 | |------|------|------| | 递归 CTE | 精确控制每个匹配项 | 处理长字符串性能下降 | | REGEXP_REPLACE | 单次操作高效 | 会丢失数字位置信息 | | 多次调用 SUBSTRING | 兼容低版本 MySQL | 代码复杂度高 |
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值