如何在子查询的结果上使用regexp?

时间:2016-04-30 10:51:35

标签: mysql regex subquery pattern-matching

我有两张桌子。

用户 其中 ID 电话号码

id phone_no

1 ---- 9912678

2 ---- 9912323

3 ---- 9912366

入场表, ID 电话号码

id phone_no

6 --- 991267823

7 --- 991236621

8 --- 435443455

9 --- 243344333

我想找到与用户表具有相同模式且更新入场表的所有电话号码 >它在用户表中。

所以我正在尝试这个

select phone_no  from admission where phone_no REGEXP (SELECT phone_no
FROM  `users` AS user
WHERE user.phone_no REGEXP  '^(99)+[0-9]{8}')

但我收到此错误子查询返回超过1行

寻求帮助。

3 个答案:

答案 0 :(得分:1)

我认为这可以做你想要的,我做了一些改进(SQLfiddle):

select * from admission a where exists (
  select * from (
     select substr(phone_no, 1, 7) pn from users where phone_no REGEXP '^99[0-9]{5}'
  ) o where a.phone_no like concat(o.pn, '%')
)

我必须修改正则表达式以获得任何匹配。如果长度固定,则可以使用like轻松完成第二次检查。我们会查看user表格,看看exists是否phone_no符合我们目前正在查看的录取号码标准。{/ p>

答案 1 :(得分:1)

别介意正则表达式。使用like

进行简单的加入
select distinct a.phone_no
from user u
join admission a on a.phone_no like concat(u.phone_no, '%')
where u.phone_no like '99%'

仅当distinct表和/或admission表中存在重复的数字时,才需要user关键字。否则,可以省略。

答案 2 :(得分:1)

尝试其中一个查询:

SELECT a.phone_no
FROM admission a
JOIN users u on a.phone_no LIKE concat(u.phone_no, '__')
WHERE u.phone_no REGEXP  '^(99)+[0-9]+$'

SELECT a.phone_no
FROM admission a
JOIN users u on a.phone_no REGEXP concat('^', u.phone_no, '[0-9]{2}$')
WHERE u.phone_no REGEXP  '^(99)+[0-9]+$'

如果“固定数字”的数量不固定,您也可以使用:

LIKE concat(u.phone_no, '%')

REGEXP concat('^', u.phone_no, '[0-9]*$')

但在这种情况下,如果SELECT DISTICT a.phone_no可能是其他users.phone_no的子序列(例如99123和991234),则可能需要使用users.phone_no

<强>更新

运行一些测试,其中10K行为用户表,100K行为准入表,我来到以下查询:

SELECT a.phone_no
FROM admission a
JOIN users u 
    ON  a.phone_no >= u.phone_no
    AND a.phone_no < CONCAT(u.phone_no, 'z')
    AND a.phone_no LIKE CONCAT(u.phone_no, '%')
    AND a.phone_no REGEXP CONCAT('^', u.phone_no, '[0-9]*$')
WHERE   u.phone_no LIKE  '99%'
    AND u.phone_no REGEXP  '^(99)+[0-9]*$'
UNION SELECT 0 FROM (SELECT 0) dummy WHERE 0

fiddle

这样您就可以使用REGEXP并且仍然可以获得出色的效果。此查询几乎立即在我的测试用例中执行。

逻辑上,您只需要REGEXP条件。但是在更大的表上,查询可能会超时。使用LIKE条件将在REGEXP检查之前过滤结果集。但即使使用LIKE查询也不是很好。出于某种原因,MySQL不对连接使用范围检查。所以我添加了一个明确的范围检查:

    ON  a.phone_no >= u.phone_no
    AND a.phone_no < CONCAT(u.phone_no, 'z')

通过此检查,您可以从JOIN部分中删除LIKE条件。

UNION部分是DISTICT的替代品。 MySQL似乎将DISTINCT转换为GROUP BY语句,该语句表现不佳。使用带有空结果集的UNION,强制MySQL在SELECT之后删除重复项。如果使用固定数量的尾随数字,则可以删除该行。

您可以根据需要调整REGEXP模式:

...
    AND a.phone_no REGEXP CONCAT('^', u.phone_no, '[0-9]{2}$')
...
    AND u.phone_no REGEXP  '^(99)+[0-9]{8}$'
...

如果您只需要REGEXP来检查phone_no的长度,您也可以使用带有'_'占位符的LIKE条件。

    AND a.phone_no LIKE CONCAT(u.phone_no, '__')
...
    AND u.phone_no LIKE '99________$'

或将LIKE条件与STR_LENGTH检查结合起来。