2011-01-10 15 views
10

To pytanie wynika z MYSQL join results set wiped results during IN() in where clause?podzielić ciąg MYSQL z GROUP_CONCAT się w (array, jak, wyrażenie, liście), że w() może zrozumieć

Tak, krótką wersję pytaniem. Jak zmienić ciąg zwracany przez GROUP_CONCAT na listę wyrażeń rozdzielonych przecinkami, która IN() będzie traktować jako listę wielu elementów do zapętlenia się?

N.B. Dokumenty MySQL wydają się odnosić do "(przecinek, oddzielne, listy)" używanych przez IN() jako "listy wyrażeń", i co ciekawe strony na IN() wydają się być mniej więcej jedynymi stronami w dokumentach MySQL, kiedykolwiek odnosić się do list wyrażeń. Więc nie jestem pewien, czy funkcje przeznaczone do tworzenia tablic lub tabel tymczasowych będą tutaj przydatne.


wersja Długi przykład oparte na pytanie: Z 2-tabeli DB tak:

SELECT id, name, GROUP_CONCAT(tag_id) FROM person INNER JOIN tag ON person.id = tag.person_id GROUP BY person.id; 
+----+------+----------------------+ 
| id | name | GROUP_CONCAT(tag_id) | 
+----+------+----------------------+ 
| 1 | Bob | 1,2     | 
| 2 | Jill | 2,3     | 
+----+------+----------------------+ 

Jak mogę włączyć ten, który ponieważ wykorzystuje ciąg jest traktowana jako logiczny odpowiednik (1 = X) i (2 x) = ...

SELECT name, GROUP_CONCAT(tag.tag_id) FROM person LEFT JOIN tag ON person.id = tag.person_id 
GROUP BY person.id HAVING ((1 IN (GROUP_CONCAT(tag.tag_id))) AND (2 IN (GROUP_CONCAT(tag.tag_id)))); 
Empty set (0.01 sec) 

... w coś, w których wynik GROUP_CONCAT jest traktowany jako listy, tak że dla Boba, byłoby równoznaczne z:

SELECT name, GROUP_CONCAT(tag.tag_id) FROM person INNER JOIN tag ON person.id = tag.person_id AND person.id = 1 
GROUP BY person.id HAVING ((1 IN (1,2)) AND (2 IN (1,2))); 
+------+--------------------------+ 
| name | GROUP_CONCAT(tag.tag_id) | 
+------+--------------------------+ 
| Bob | 1,2      | 
+------+--------------------------+ 
1 row in set (0.00 sec) 

... i Jill, byłoby równoznaczne z:

SELECT name, GROUP_CONCAT(tag.tag_id) FROM person INNER JOIN tag ON person.id = tag.person_id AND person.id = 2 
GROUP BY person.id HAVING ((1 IN (2,3)) AND (2 IN (2,3))); 
Empty set (0.00 sec) 

... więc ogólny wynik byłby wyłącznym klauzula wyszukiwania wymagające wszystkie wymienione znaczniki, które nie korzystają HAVING COUNT (ODRĘBNY ...) ?

(uwaga: Ta logika działa bez I, stosując do pierwszego znaku łańcucha np

SELECT name, GROUP_CONCAT(tag.tag_id) FROM person LEFT JOIN tag ON person.id = tag.person_id 
    GROUP BY person.id HAVING ((2 IN (GROUP_CONCAT(tag.tag_id)))); 
+------+--------------------------+ 
| name | GROUP_CONCAT(tag.tag_id) | 
+------+--------------------------+ 
| Jill | 2,3      | 
+------+--------------------------+ 
1 row in set (0.00 sec) 
+1

To jest ładne, ale warto zauważyć, że nie trzeba robić 'GROUP_CONCAT()' we wszystkich 'FIND_IN_SET()'. Możesz po prostu "SELECT GROUP_CONCAT (tag.tag_id) AS tag_list", a następnie 'HAVING FIND_IN_SET (20, tags_list)' – Treffynnon

Odpowiedz

33

Zamiast IN(), by za pomocą FIND_IN_SET() być rozwiązaniem zbyt

http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_find-in-set

.?
mysql> SELECT FIND_IN_SET('b','a,b,c,d'); 
    -> 2 

Oto pełny przykład na podstawie przykładowego problemu w kwestii, potwierdzony jako przetestowany przez pytającego we wcześniejszej edycji na pytanie:

SELECT name FROM person LEFT JOIN tag ON person.id = tag.person_id GROUP BY person.id 
    HAVING (FIND_IN_SET(1, GROUP_CONCAT(tag.tag_id))) AND (FIND_IN_SET(2, GROUP_CONCAT(tag.tag_id))); 
+------+ 
| name | 
+------+ 
| Bob | 
+------+ 
+0

Dziękujemy! Ja też tego potrzebuję. –

+0

Idealny! Jedna wskazówka: nie zapominaj, że skoro jest to jak wywołanie funkcji, nie może być ** żadnej spacji przed nawiasem otwierającym/nawiasem, ** w przeciwnym razie pojawi się błąd 'Funkcja nazwa_bazy_danych.FIND_IN_SET nie istnieje." – user568458

+0

Cóż, jest to rozwiązanie, ale odkryłem, że funkcja FIND_IN_SET jest wyjątkowo mniej wydajna niż IN, to ... czy wiesz, czy istnieje sposób na osiągnięcie tego, co mówi pytanie, sposób podziału ciągu na tablicę? zmienna? –

4

można przekazać ciąg jako tablicę, używając separatora podziału i eksplodować go w funkcja, która będzie działać z wynikami.

Dla trywialny przykład, jeśli masz tablicę ciągów tak: „jeden | dwa | drzewo | cztery | pięć”, i chcę wiedzieć, czy dwa jest w tablicy, można to zrobić w ten sposób:

create function str_in_array(split_index varchar(10), arr_str varchar(200), compares varchar(20)) 
    returns boolean 
    begin 
    declare resp boolean default 0; 
    declare arr_data varchar(20); 

    -- While the string is not empty 
    while(length(arr_str) > 0 ) do 

    -- if the split index is in the string 
    if(locate(split_index, arr_str)) then 

     -- get the last data in the string 
    set arr_data = (select substring_index(arr_str, split_index, -1)); 

    -- remove the last data in the string 
    set arr_str = (select 
     replace(arr_str, 
     concat(split_index, 
      substring_index(arr_str, split_index, -1) 
     ) 
     ,'') 
    ); 
    -- if the split index is not in the string 
    else 
    -- get the unique data in the string 
    set arr_data = arr_str; 
    -- empties the string 
    set arr_str = ''; 
    end if; 

    -- in this trivial example, it returns if a string is in the array 
    if arr_data = compares then 
    set resp = 1; 
    end if; 

end while; 

return resp; 
end 
| 

delimiter ; 

Chcę utworzyć zestaw użytecznych funkcji mysql do pracy z tą metodą. Zainteresowanych proszę o kontakt.

Więcej przykładów można znaleźć http://blog.idealmind.com.br/mysql/how-to-use-string-as-array-in-mysql-and-work-with/