2016-04-30 62 views
1

我有两个表。如何对子查询的结果使用regexp?

用户 ,其具有ID电话号码


IDphone_no

1 ---- 9912678

2 ---- 9912323

3 ---- 9912366


入场表,其具有ID电话号码

IDphone_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行

寻找帮助。

+1

你是什么意思,确切地说,“具有相同的模式”?从你的例子猜测,它实际上是“开始于”吗? – Bohemian

+0

用户表和入场表都有相同的电话号码,以99开始,但用户表缺少结尾2位数。首先,我想过滤来自入场表'^ [99] + [0-9] {8}'的所有这些号码,然后将用户的电话号码9912678与入场的电话号码991267823 – shuvrow

+0

匹配,如果我以这种方式查询用户表格的数据'9912678 | 9912323 | 9912366'查询执行正常,但我不知道该怎么做。谢谢 – shuvrow

回答

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]*$') 

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

更新

后运行一些测试用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') 

有了这个检查可以从连接的一部分去除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检查相结合。

+0

不使用'DISTINCT'而使用'LIKE'将会返回重复项,最好使用'EXISTS'而不是加入表。 – maraca

+0

谢谢@maraca。然而,只有“DISTINCT”才需要,如果“尾随数字”的数量不固定。 –

+0

@PaulSpiegel你的第一个查询返回空结果,第二个查询返回更多的值,然后入场表和第三个工作正常。谢谢 – shuvrow

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匹配我们目前正在查看的入场号码的标准。

+0

谢谢它的工作:) – shuvrow

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表。否则,它可以省略。

+0

对不起,但是由于查询是错误的,并且确实存在他所抱怨的问题:电话号码将会成倍增加(除非您做出明确的决定)。 – maraca

+0

@maraca你错了。错误OP正在变得与返回结果中的重复行无关;这是由于OP的*子查询*在查询中作为单值结果使用时返回多行。在OP的查询中使用'distinct'不会使OP的错误消失。在我的查询中使用'distinct'只会在原始数据中有重复时才需要(我已经更新了我的答案以解释这一点)。 – Bohemian

+0

@maraca,我不同意你所说的一切。要明确的是,如果两个入场号码都匹配(即开始)相同的用户号码,则根据OP的要求,它们都在输出中预期。正如我之前所说的,只有在任何一个表中都有实际重复的情况下,输出才会出现重复。此外,“like”是完全合适的,因为语义是“开始于”,这是最简单,最好和最清楚地表示为“like”前缀%“'。使用'exists'会表现的非常糟糕,因为它必须为每一行执行一次子查询,而'like'只使用1次。 – Bohemian

相关问题