Czy mogę połączyć wiele wierszy MySQL w jedno pole?

1214

Używając MySQL, mogę zrobić coś takiego:

SELECT hobbies FROM peoples_hobbies WHERE person_id = 5;

Mój wynik:

shopping
fishing
coding

ale zamiast tego chcę tylko 1 wiersz, 1 kolumnę:

Oczekiwany wynik:

shopping, fishing, coding

Powodem jest to, że wybieram wiele wartości z wielu tabel, a po wszystkich połączeniach mam o wiele więcej wierszy, niż bym chciał.

Szukałem funkcji w MySQL Doc i nie wygląda ona na to, że funkcje CONCATlub CONCAT_WSakceptują zestawy wyników.

Czy ktoś tu wie, jak to zrobić?

Dean Rather
źródło
9
Właśnie napisałem małe demo na temat korzystania z group_concat, które może ci się przydać
Marc Giombetti

Odpowiedzi:

1737

Możesz użyć GROUP_CONCAT:

SELECT person_id, GROUP_CONCAT(hobbies SEPARATOR ', ')
FROM peoples_hobbies
GROUP BY person_id;

Jak stwierdził Ludwig w swoim komentarzu, możesz dodać DISTINCToperatora, aby uniknąć duplikatów:

SELECT person_id, GROUP_CONCAT(DISTINCT hobbies SEPARATOR ', ')
FROM peoples_hobbies 
GROUP BY person_id;

Jak stwierdził Jan w komentarzu, możesz także posortować wartości przed zaimplementowaniem ich za pomocą ORDER BY:

SELECT person_id, GROUP_CONCAT(hobbies ORDER BY hobbies ASC SEPARATOR ', ')
FROM peoples_hobbies
GROUP BY person_id;

Jak stwierdził Dag w swoim komentarzu, wynik ma limit 1024 bajtów. Aby rozwiązać ten problem, uruchom zapytanie przed zapytaniem:

SET group_concat_max_len = 2048;

Oczywiście możesz zmienić w 2048zależności od potrzeb. Aby obliczyć i przypisać wartość:

SET group_concat_max_len = CAST(
    (SELECT SUM(LENGTH(hobbies)) + COUNT(*) * LENGTH(', ')
    FROM peoples_hobbies 
    GROUP BY person_id)
    AS UNSIGNED
);
che
źródło
154
Wystarczy pamiętać o ograniczeniu 1024 bajtów w wynikowej kolumnie (patrz parametr group_concat_max_len )
Dag
81
Dodając DISTINCTparametr, nie dostaniesz żadnych wyników podwójnych. ... GROUP_CONCAT(DISTINCT hobbies)
Ludwig
3
Chciałem uzyskać WSZYSTKIE dane z jednej kolumny. Nie używaj do tego klauzuli GROUP BY. Przykład: SELECT GROUP_CONCAT (e-mail SEPARATOR ',') OD użytkowników;
Jonathan Bergeron
1
Dzięki, nie wiedziałem, że istnieje limit długości konkat grupy. Potrzebowałem tego, aby obejść wygenerowaną listę potworów.
Patrick
9
Jeśli chcesz hobby sortowania w otrzymanej implodowała użycia strun:SELECT person_id, GROUP_CONCAT(hobbies ORDER BY hobbies ASC SEPARATOR ', ') FROM peoples_hobbies GROUP BY person_id
Jan
106

Sprawdź, GROUP_CONCATczy Twoja wersja MySQL (4.1) ją obsługuje. Więcej informacji znajduje się w dokumentacji .

Wyglądałoby to tak:

  SELECT GROUP_CONCAT(hobbies SEPARATOR ', ') 
  FROM peoples_hobbies 
  WHERE person_id = 5 
  GROUP BY 'all';
lpfavreau
źródło
11
Myślę, że group by 'all'nie jest to konieczne (zresztą niepożądane), ponieważ to przypisuje ciąg do wszystkich wierszy, alla następnie porównuje ciągi między tymi wierszami. Czy mam rację?
Krzysiek,
74

Alternatywna składnia do łączenia wielu pojedynczych wierszy

OSTRZEŻENIE: Ten post spowoduje, że będziesz głodny.

Dany:

Zauważyłem, że chcę wybrać wiele pojedynczych wierszy - zamiast grupy - i połączyć w jedno pole.

Załóżmy, że masz tabelę identyfikatorów produktów oraz ich nazw i cen:

+------------+--------------------+-------+
| product_id | name               | price |
+------------+--------------------+-------+
|         13 | Double Double      |     5 |
|         14 | Neapolitan Shake   |     2 |
|         15 | Animal Style Fries |     3 |
|         16 | Root Beer          |     2 |
|         17 | Lame T-Shirt       |    15 |
+------------+--------------------+-------+

Potem masz jakieś fantazyjne-schmancy ajax, które wymienia te szczeniaki jako pola wyboru.

Twój głodny hipopotam wybiera 13, 15, 16. Dziś nie ma dla niej deseru ...

Odnaleźć:

Sposób na podsumowanie zamówienia użytkownika w jednym wierszu za pomocą czystego mysql.

Rozwiązanie:

Skorzystaj GROUP_CONCATz tej INklauzuli :

mysql> SELECT GROUP_CONCAT(name SEPARATOR ' + ') AS order_summary FROM product WHERE product_id IN (13, 15, 16);

Które wyjścia:

+------------------------------------------------+
| order_summary                                  |
+------------------------------------------------+
| Double Double + Animal Style Fries + Root Beer |
+------------------------------------------------+

Rozwiązanie premiowe:

Jeśli chcesz również cenę całkowitą, wrzuć SUM():

mysql> SELECT GROUP_CONCAT(name SEPARATOR ' + ') AS order_summary, SUM(price) AS total FROM product WHERE product_id IN (13, 15, 16);
+------------------------------------------------+-------+
| order_summary                                  | total |
+------------------------------------------------+-------+
| Double Double + Animal Style Fries + Root Beer |    10 |
+------------------------------------------------+-------+

PS: Przepraszam, jeśli nie masz w pobliżu wejścia i wyjścia ...

elbowlobstercowstand
źródło
11
Mimo że jest to dobra odpowiedź, brzmi to bardziej jak reklama niż zwykła odpowiedź. Wciąż dobra, dobrze sformułowana odpowiedź.
FliiFe,
1
Mogę uzyskać pomoc stackoverflow.com/q/60278898/11697039 @elbowlobstercowstand
ZUS
39

Możesz zmienić maksymalną długość GROUP_CONCATwartości, ustawiając group_concat_max_lenparametr.

Zobacz szczegóły w dokumentacji MySQL .

pau.moreno
źródło
25

W moim przypadku miałem wiersz identyfikatorów i konieczne było rzutowanie go na char, w przeciwnym razie wynik został zakodowany w formacie binarnym:

SELECT CAST(GROUP_CONCAT(field SEPARATOR ',') AS CHAR) FROM table
Fedir RYKHTIK
źródło
1
Dzięki! Bez CASTmiałem takie wartości jak [BLOB - 14 Bytes]w wyniku!
Mel_T
1
Mogę uzyskać pomoc stackoverflow.com/q/60278898/11697039 @Fedir RYKHTIK
ZUS
16

Użyj zmiennej sesji MySQL (5.6.13) i operatora przypisania, jak poniżej

SELECT @logmsg := CONCAT_ws(',',@logmsg,items) FROM temp_SplitFields a;

wtedy możesz dostać

test1,test11
Shen Liang
źródło
2
czy jest szybszy niż GROUP_CONCAT?
jave.web
1
Przetestowałem to pod PHPMyAdmin z serwerem MySQL v5.6.17 w kolumnie opisu (varchar (50)) w tabeli testowej, ale zwraca pole BLOB dla każdego rekordu:SELECT @logmsg := CONCAT_ws(',',@logmsg,description) from test
stycznia
14

Miałem bardziej skomplikowane zapytanie i stwierdziłem, że musiałem użyć GROUP_CONCATzewnętrznego zapytania, aby go uruchomić:

Oryginalne zapytanie:

SELECT DISTINCT userID 
FROM event GROUP BY userID 
HAVING count(distinct(cohort))=2);

Wszczepiony:

SELECT GROUP_CONCAT(sub.userID SEPARATOR ', ') 
FROM (SELECT DISTINCT userID FROM event 
GROUP BY userID HAVING count(distinct(cohort))=2) as sub;

Mam nadzieję, że to może komuś pomóc.

Alex Bowyer
źródło
9

Dla kogoś, kto szuka tutaj sposobu korzystania GROUP_CONCATz podzapytania - opublikowanie tego przykładu

SELECT i.*,
(SELECT GROUP_CONCAT(userid) FROM favourites f WHERE f.itemid = i.id) AS idlist
FROM items i
WHERE i.id = $someid

Dlatego GROUP_CONCATnależy go używać wewnątrz podzapytania, a nie owijania go.

Oleg Abrazhaev
źródło
1
Właśnie tego szukałem
bumerang
7

Spróbuj tego:

DECLARE @Hobbies NVARCHAR(200) = ' '

SELECT @Hobbies = @Hobbies + hobbies + ',' FROM peoples_hobbies WHERE person_id = 5;
thejustv
źródło
2
Oto, co otrzymałem: „Nierozpoznany typ instrukcji. (w pobliżu „DECLARE” na pozycji 0) ”
Istiaque Ahmed
1

mamy dwa sposoby konkatenacji kolumn w MySql

select concat(hobbies) as `Hobbies` from people_hobbies where 1

Lub

select group_concat(hobbies) as `Hobbies` from people_hobbies where 1
raghavendra
źródło