Jak używać GROUP_CONCAT w CONCAT w MySQL

117

Jeśli mam tabelę z następującymi danymi w MySQL:

id       Name       Value
1          A          4
1          A          5
1          B          8
2          C          9

jak uzyskać to w następującym formacie?

id         Column
1          A:4,5,B:8
2          C:9


Myślę, że muszę użyć GROUP_CONCAT. Ale nie jestem pewien, jak to działa.

Biswa
źródło

Odpowiedzi:

160
select id, group_concat(`Name` separator ',') as `ColumnName`
from
(
  select 
    id, 
    concat(`Name`, ':', group_concat(`Value` separator ',')) as `Name`
  from mytbl
  group by 
    id, 
    `Name`
) tbl
group by id;

Możesz zobaczyć to zaimplementowane tutaj: Sql Fiddle Demo . Dokładnie to, czego potrzebujesz.

Zaktualizuj podział w dwóch krokach. Najpierw otrzymujemy tabelę zawierającą wszystkie wartości (oddzielone przecinkami) względem unikalnego [Nazwa, identyfikator]. Następnie z uzyskanej tabeli otrzymujemy wszystkie nazwy i wartości jako jedną wartość dla każdego unikalnego identyfikatora Zobacz to wyjaśnione tutaj SQL Fiddle Demo (przewiń w dół, ponieważ ma dwa zestawy wyników)

Edytuj Wystąpił błąd w czytaniu pytania, pogrupowałem tylko według identyfikatora. Ale dwa group_contacts są potrzebne, jeśli (wartości mają być połączone pogrupowane według nazwy i identyfikatora, a następnie według identyfikatora). Poprzednia odpowiedź brzmiała

select 
id,group_concat(concat(`name`,':',`value`) separator ',')
as Result from mytbl group by id

Możesz zobaczyć to zaimplementowane tutaj: SQL Fiddle Demo

Sami
źródło
To nie daje tego, o co prosił Biswa.
eisberg
3
Myślę, że ważne jest, aby ostrzec ludzi, że używanie tylko jednego rodzaju separatora może być niekorzystne. Sugeruję, aby separator „nazwa” był średnikiem (;), a separator wartości mógł pozostać przecinkiem (,)
Fandi Susanto
4
Należy również pamiętać, że GROUP_CONCATmoże to po cichu obciąć swoje dane wyjściowe do group_concat_max_len. SET group_concat_max_len=...pomoże, ale i tak dobrze jest sprawdzić, czy zwracana (bajtowa?) długość jest mniejsza niż group_concat_max_len.
tuomassalo,
2
Zauważ również, że group_concat napotka pojedynczą wartość NULL i pominie cały wiersz, który ją zawiera. Obejdę to w drugim zastrzeżeniu tutaj .
MatrixManAtYrService,
1
Jeśli ktoś ma problem z odsyłaczem SQL Fiddle podanym w odpowiedzi. Fiddle robocza jest tutaj: sqlfiddle.com/#!9/42f994/601/0
Hitesh
21

Próbować:

CREATE TABLE test (
  ID INTEGER,
  NAME VARCHAR (50),
  VALUE INTEGER
);

INSERT INTO test VALUES (1, 'A', 4);
INSERT INTO test VALUES (1, 'A', 5);
INSERT INTO test VALUES (1, 'B', 8);
INSERT INTO test VALUES (2, 'C', 9);

SELECT ID, GROUP_CONCAT(NAME ORDER BY NAME ASC SEPARATOR ',')
FROM (
  SELECT ID, CONCAT(NAME, ':', GROUP_CONCAT(VALUE ORDER BY VALUE ASC SEPARATOR ',')) AS NAME
  FROM test
  GROUP BY ID, NAME
) AS A
GROUP BY ID;

SQL Fiddle: http://sqlfiddle.com/#!2/b5abe/9/0

eisberg
źródło
2
Tak eisberg +1. Twoja odpowiedź jest dość dokładna i wcześniejsza. Popełniłem błąd w mojej pierwszej odpowiedzi
Sami
9
SELECT ID, GROUP_CONCAT(CONCAT_WS(':', NAME, VALUE) SEPARATOR ',') AS Result 
FROM test GROUP BY ID
Jan
źródło
7
Byłoby miło, gdybyś mógł dodać opis do swojej odpowiedzi. To jest sugestia, aby poprawić tę i przyszłe odpowiedzi. Dzięki!
Luís Cruz
5

Po pierwsze, nie widzę powodu posiadania identyfikatora, który nie jest unikalny, ale wydaje mi się, że jest to identyfikator, który łączy się z inną tabelą. Po drugie, nie ma potrzeby wykonywania podzapytań, które pobudzają serwer. Robisz to w jednym zapytaniu, jak to

SELECT id,GROUP_CONCAT(name, ':', value SEPARATOR "|") FROM sample GROUP BY id

Uzyskujesz szybkie i poprawne wyniki, a wynik można podzielić przez SEPARATOR „|”. Zawsze używam tego separatora, ponieważ nie można go znaleźć w ciągu, dlatego jest wyjątkowy. Nie ma problemu z dwoma A, identyfikujesz tylko wartość. Albo możesz mieć jeszcze jedną kolumnę z literą, co jest jeszcze lepsze. Lubię to :

SELECT id,GROUP_CONCAT(DISTINCT(name)), GROUP_CONCAT(value SEPARATOR "|") FROM sample GROUP BY name
Lucian Minea
źródło
2
 SELECT id, GROUP_CONCAT(CONCAT_WS(':', Name, CAST(Value AS CHAR(7))) SEPARATOR ',') AS result 
    FROM test GROUP BY id

musisz użyć rzutowania lub konwersji, w przeciwnym razie zostanie zwrócony BLOB

wynik jest

id         Column
1          A:4,A:5,B:8
2          C:9

musisz ponownie obsłużyć wynik przez program taki jak python lub java

lglcomcn
źródło
0

IF OBJECT_ID('master..test') is not null Drop table test

CREATE TABLE test (ID INTEGER, NAME VARCHAR (50), VALUE INTEGER );
INSERT INTO test VALUES (1, 'A', 4);
INSERT INTO test VALUES (1, 'A', 5);
INSERT INTO test VALUES (1, 'B', 8);
INSERT INTO test VALUES (2, 'C', 9);

select distinct NAME , LIST = Replace(Replace(Stuff((select ',', +Value from test where name = _a.name for xml path('')), 1,1,''),'<Value>', ''),'</Value>','') from test _a order by 1 desc

Nazwa mojej tabeli to test, a do łączenia używam składni For XML Path (''). Funkcja stuff wstawia ciąg do innego ciągu. Usuwa określoną długość znaków w pierwszym ciągu w pozycji początkowej, a następnie wstawia drugi ciąg do pierwszego ciągu w pozycji początkowej.

Funkcje STUFF wyglądają następująco: STUFF (wyrażenie_znaku, początek, długość, wyrażenie_znaku)

znak_wyrażenie Jest wyrażeniem danych znakowych. wyrażenie_znakowe może być stałą, zmienną lub kolumną zawierającą dane znakowe lub binarne.

start Jest liczbą całkowitą określającą lokalizację rozpoczęcia usuwania i wstawiania. Jeśli początek lub długość jest ujemna, zwracany jest ciąg pusty. Jeśli początek jest dłuższy niż pierwszy znak_wyrażenie, zwracany jest łańcuch o wartości null. początek może być typu bigint.

długość Jest liczbą całkowitą określającą liczbę znaków do usunięcia. Jeśli długość jest większa niż pierwsze wyrażenie_znaku, usuwanie następuje aż do ostatniego znaku w ostatnim wyrażeniu_znaku. długość może być typu bigint.

Novy
źródło
0

SELECT id, Group_concat ( column) FROM (SELECT id, Concat ( name, ':', Group_concat ( value)) AS column FROM mytbl GROUP BY id, name) tbl GROUP BY id;

Mrigank Shekhar
źródło