mysql中的子字符串正则表达式匹配

Posted

技术标签:

【中文标题】mysql中的子字符串正则表达式匹配【英文标题】:Substring regex matching in mysql 【发布时间】:2021-03-02 14:04:42 【问题描述】:

我有一个复杂的问题困扰了我几个小时,并寻求 mysql 专家的帮助。 :) 提前谢谢你。

表:t1;列:名称

给定表格:

name
-----
$abc|def|$cde
efd|$acd
$gcb|$bvv|ggg

预期结果(只拉取不带$前缀的字符串,管道表示字段值分隔符):

name
-----
def
efd
ggg
-- Sql to create and insert
create table t1 (name varchar(100));
        insert into t1 (name) values ('$abc|def|$cde');
        insert into t1 (name) values ('efd|$acd');
        insert into t1 (name) values ('$gcb|$bvv|ggg');

Mysql版本:5.6.40

【问题讨论】:

1) 考虑不在表中存储管道分隔的数据,2) 考虑升级到 MySQL 8+。这个查询在 MySQL 5 上会很难看。 每列值的单独“管道”值的最大数量是多少? 【参考方案1】:
SELECT DISTINCT
       name, SUBSTRING_INDEX(SUBSTRING_INDEX(t1.name, '|', num), '|', -1) one_value
FROM t1
/* max 3 subnames per name - expand if needed */
CROSS JOIN (SELECT 1 num UNION SELECT 2 UNION SELECT 3) numbers
HAVING one_value NOT LIKE '$%';

fiddle

【讨论】:

@amine 在这种情况下考虑接受这个答案。 抱歉,有时需要消化并使用更多子名称,我已附加一个新条目 $gcb|$bvv|$ggg|$ste|sgg 并在其中添加联合更多子名称。查询结果确实返回一些重复项。这是此查询的预期行为,如果这是预期行为,我稍后可以将它们传递给不同的函数以删除欺骗。 dbfiddle.uk/… :) @amine 最简单的解决方案 - SELECT DISTINCT ...。已更新。【参考方案2】:

在 MySQL 8+ 上,您可以尝试:

SELECT
    col,
    REGEXP_REPLACE(CONCAT('|', col, '|'), '^.*\\|([a-z]+)\\|.*$', '$1') AS col_out
FROM yourTable;

这里的想法是从这个稍微修改的列值开始:

|$abc|def|$cde|

然后,我们搜索由管道包围的仅字母序列,并替换为捕获的组。

Demo

【讨论】:

@Akina 感谢您的反馈,我最初是在手机上回答的,因此无法进行任何测试。问题是元字符在调用REGEXP_REPLACE 时似乎需要双重转义。更新的版本现在可以使用了。 如果有多个没有$ 的子值,那么只会返回最后一个...从另一边来看,OP 不会显示这样的值。 现在您看到了我们甚至不希望出现的边缘情况。如果可能有多个匹配项,那么 OP 绝对应该 规范化 数据并停止以这种方式存储它。一列值应生成一个输出值。 感谢 Akina 和 Tim,非常感谢您提供的代码和反馈,并进行思考。它只是该领域的一个子值(我的错,应该早点澄清)。代码很清楚,非常感谢你,我希望。不幸的是,我仍然必须坚持使用旧的 mysql 版本,直到我真的希望我们有机会升级它。

以上是关于mysql中的子字符串正则表达式匹配的主要内容,如果未能解决你的问题,请参考以下文章

正则的学习

正则表达式之量词

JAVA正则表达式怎么匹配所有符合要求的子字符串

java中的正则表达式

js中的正则表达式入门

正则表达式在java中的应用