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ć?


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
);

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';

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 ...


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



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

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

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.


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.


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;

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.