无论顺序如何,REGEX都匹配另一个组列表中的组字符串 - SQL

时间:2012-12-21 10:50:50

标签: mysql sql regex group-concat

以下是该方案。如何利用REGEXP来模拟IN运算符,但匹配右侧左侧的所有值,而不管任何一方的字符串顺序如何。使用左连接和子查询也可以实现ANSI SQL解决方案。

样本表:

Parent table, Child table, Parent_Child。为了不在问题上占用更多空间,我只在这里发布了Group_Concat Child query by Parent的最新信息。

PID     NAME        CHILDREN    
1       dad john    dave,jill,lina
2       mum sandy   maryam,jack 
3       dad frank   henry,jill 
4       mum kate    maryam  
5       mum jean    dave

预期结果:选择让所有孩子都参与其中的家长。

PID     NAME        CHILDRENREXGEX
3       dad frank   jill,henry
4       mum kate    maryam
5       mum jean    dave

这是REGEXP SQL解决方案:现在问题是,如果左侧订单/顺序与右侧不匹配,则不会返回正确的结果。

查询:

select 
    x.pid, x.name, x.children as childrenRexgex
from
    (select 
         p.pid, p.name, group_concat(c.name) as children
     from 
         parent as p
     inner join 
         parent_child as pc on p.pid = pc.pid
     join 
         child as c on pc.cid = c.cid
     group by 
         p.pid
     order by 
         c.name) as x
where 
    'dave,maryam,jill,henry' REGEXP x.children
;

因此,我对这个问题有两个方面的感谢:

  1. 无论订单如何,将左侧所有名称与用户定义的右侧列表匹配的最佳模式是什么?
  2. 使用REGEXP获得的效果可能是什么?

1 个答案:

答案 0 :(得分:2)

你想使用正则表达式,还是其他解决方案还可以? 如果我理解正确,这个查询应该给你正确的结果:

select p.pid, parent.name, group_concat(child.name)
from
  (select pid
   from 
     parent_child inner join child
     on parent_child.cid = child.cid
   group by pid
   having sum(child.name in ('dave','henry','maryam','jill'))=count(*)) p
  inner join parent on p.pid=parent.pid
  inner join parent_child on p.pid=parent_child.pid
  inner join child on parent_child.cid=child.cid
group by p.pid

给出:

PID     NAME        CHILDRENREXGEX
3       dad frank   jill,henry
4       mum kate    maryam
5       mum jean    dave

无论如何,要使用您的解决方案,我建议您使用group_concat订单:

select
  x.pid,
  x.name,
  x.children as childrenRexgex
from(
  select
    p.pid,
    p.name, 
    group_concat(c.name order by c.name) as children,
    count(c.name) as counts
  from
    parent as p inner join parent_child as pc
    on p.pid = pc.pid
    join child as c
    on pc.cid = c.cid
  group by p.pid) as x
where 'dave,henry,jill,maryam'
  REGEXP x.children

并尝试匹配已订购的名称。这与您的查询相同,我只在group_concat中添加了order by c.name,并且我还在where条件中对字符串进行了排序。

编辑:如果你真的想使用REGEXP,由于对正则表达式的MySql支持有限,我建议你尝试使用LIB_MYSQLUDF_PREG。这是一个通用的解决方案,不适用于标准的MySql正则表达式。

如果你需要匹配这样的字符串:

One,Two,Three,Four
例如,

Two,Four,Three,One

你必须使用像这样的正则表达式:

"One,Two,Three,Four" REGEXP
"^(?=.*\bTwo\b)(?=.*\bFour\b)(?=.*\bThree\b)(?=.*\bOne\b)"

check this question)这就是它的作用:

  1. \bTwo\b匹配完整字词2,可以是:Two Two, ,Two ,Two,
  2. .*字词2可以在字符串.*\bTwo\b
  3. 中找到
  4. (?=.*\bTwo\b)匹配字符串中的完整字词2,  但是忘记了这个位置并从头开始学习下一学期
  5. 开始匹配其他单词
  6. 仍然缺少什么?是的,因为如果我们匹配"One,Two,Three,Four""One,Two,Three,Four,Five"也会匹配。也许有一个更好的正则表达式,但我的想法是:如果它们匹配,并且具有相同的长度,它们必须是相同的,除了订单。所以我们可以在regexp的末尾添加它:

    1. .{length}$请记住,在之前的所有比赛之后,我们仍处于开头,^.{length}$匹配给定长度的字符串
    2. 所以最终的代码是:

      field1="One,Two,Three,Four"
      field2="Two,Four,Three,One"
      
      field1 REGEXP CONCAT("^(?=.*\b", 
                           REPLACE(field2, ",", "\b)(?=.*\b"),
                           "\b).{", LENGTH(field1), "}$")
      

      请注意,REGEXP 不支持此正则表达式,LIB_MYSQLUDF_PREG应支持它,但我仍未对其进行测试。我会让你知道。可能还有其他解决方案,但我认为只用REGEXP就可以做得更好。