2012-12-21 14 views
5

Oto scenariusz. Jak wykorzystać REGEXP do symulowania operatora IN jeszcze do pasuje do wszystkich wartości po lewej stronie po prawej stronie, niezależnie od kolejności ciągów po obu stronach. Również rozwiązanie ANSI SQL może zostać osiągnięte za pomocą lewostronnego połączenia i podrzędnych zapytań.REGEXP, aby dopasować ciąg grupy w obrębie innej listy grup bez względu na kolejność - SQL

stół próbki:

Parent table, Child table, Parent_Child. Aby nie zajmować więcej miejsca w tym pytaniu, zamieszczam tutaj tylko numer 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 

Oczekiwany wynik: Wybierz rodzica, który ma swoje wszystkie dzieci uczestniczyły w czymś.

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

Oto rozwiązanie REGEXP SQL: teraz problem tutaj, to nie zwraca poprawne wyniki, jeśli zamówienie lewa strona/squence nie pasuje do prawej strony.

Zapytanie:

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 
; 

Stąd istnieją dwa aspekty Byłbym wdzięczny za to pytanie:

  1. Jaki jest najlepszy wzorzec dopasować wszystkie nazwy w lewym boku do listy zdefiniowanych przez użytkownika prawa strona bez względu na kolejność?
  2. Jaka może być wydajność uzyskana za pomocą REGEXP?
+0

Prawdziwy problem polega na tym, że dzieci nie powinny być kolumną z oddzielonymi przecinkami, ale powinny być tabelą szczegółów. Zobacz to pytanie: [Czy przechowywanie ograniczonej listy w kolumnie bazy danych jest naprawdę złe?] (Http://stackoverflow.com/questions/3653462/is-storing-a-delimited-list-in-a-database-column- naprawdę-tak-źle) –

Odpowiedz

2

Czy chcesz użyć wyrażenia regularnego, czy też inne rozwiązanie jest w porządku? Jeśli dobrze rozumiem, to zapytanie powinno dać poprawny wynik:

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 

który daje:

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

W każdym razie, aby korzystać z rozwiązania, chciałbym zaproponować wam używać group_concat z rozkazem:

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 

i spróbuj dopasować nazwy już zamówione. Jest to identyczne z zapytaniem, dodałem tylko order by c.name wewnątrz group_concat, a także zamówiłem ciąg znaków w warunku where.

Edit: Jeśli naprawdę chcesz używać REGEXP, ponieważ MySQL wsparcie dla wyrażeń regularnych jest ograniczona, chciałbym zaproponować, aby spróbować użyć LIB_MYSQLUDF_PREG. Jest to ogólne rozwiązanie, które nie działa ze standardowymi wyrażeniami regularnymi MySql.

Jeśli trzeba dopasować ciąg tak:

One,Two,Three,Four 

, na przykład, tak:

Two,Four,Three,One 

trzeba użyć wyrażenia regularnego jak ten:

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

(check this question) A to, co robi:

  1. \bTwo\b mecze pełne słowo Dwa, może być: TwoTwo,,Two,Two,
  2. .* słowo Dwa można znaleźć w dowolnym miejscu w ciągu .*\bTwo\b
  3. (?=.*\bTwo\b) mecz pełen słowo Dwa, gdziekolwiek w łańcuchu, jednak zapomnieć o lokalizacji i zacznij machować następny termin od początku
  4. zacznij pasować do innych słów

Nadal czegoś brakuje? Tak, ponieważ jeśli mamy mecz dla "One,Two,Three,Four", również dopasujemy "One,Two,Three,Four,Five". Być może istnieje lepszy regexp, ale moim pomysłem jest: jeśli pasują i mają taką samą długość, muszą być identyczne, z wyjątkiem kolejności. Tak więc możemy dodać to na koniec naszej regexp:

  1. .{length}$ pamiętać, że po wszystkich poprzednich meczach, nadal jesteśmy na początku, a ^.{length}$ dopasowuje ciąg danej długości

Więc ostateczny kod byłoby:

field1="One,Two,Three,Four" 
field2="Two,Four,Three,One" 

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

Zauważ, że ten regexp nie jest obsługiwany przez rEGEXP, to powinny być wspierane na LIB_MYSQLUDF_PREG ale nadal jej nie testowane. Dam ci znać. Mogą istnieć inne rozwiązania, ale nie sądzę, że można to zrobić lepiej dzięki REGEXP.

+0

Dzięki za wysiłek. Mam już dwa zapytania, które dają mi odpowiedź bez 'regexp'. Infact jest dokładnie taki sam jak twoje pierwsze zapytanie. Więc główny powód, dla którego zamieszczam pytanie, aby uzyskać odpowiedź, rozwiązanie oparte na 'regexp' :-) być może muszę podkreślić to na moje pytanie. Jestem bardziej ciekawy, aby poznać wydajność między dwiema różnymi metodami. – bonCodigo

+0

@bonCodigo i nie byłam pewna, że ​​to było potrzebne ... pomysł użycia tylko regexp jest fajny .. nie mam jeszcze odpowiedzi, ale pomyślę o tym :) +1 za pytanie – fthiella

+0

dużo doceniłem wszelkie skuteczne informacje na temat rozwiązania 'regexp' :) W rzeczywistości sprawdziłem jeden z poprzednich postów, na które odpowiedziałeś. [Odnośnik] (http: // stackoverflow.com/questions/10480568/wartości rozdzielone przecinkami-in-mysql-in-klauzula/13445491 # 13445491) – bonCodigo

Powiązane problemy