วิธีใช้ GROUP_CONCAT ใน CONCAT ใน MySQL


117

หากฉันมีตารางที่มีข้อมูลต่อไปนี้ใน MySQL:

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

ฉันจะทำให้เป็นรูปแบบต่อไปนี้ได้อย่างไร

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


คิดว่าต้องใช้GROUP_CONCAT. แต่ฉันไม่แน่ใจว่ามันทำงานอย่างไร

คำตอบ:


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;

คุณสามารถดูได้ดำเนินการที่นี่: Sql ซอสาธิต สิ่งที่คุณต้องการ

อัปเดตการ แยกในสองขั้นตอน อันดับแรกเราได้ตารางที่มีค่าทั้งหมด (คั่นด้วยจุลภาค) เทียบกับ [Name, id] ที่ไม่ซ้ำกัน จากตารางที่ได้รับเราได้รับชื่อและค่าทั้งหมดเป็นค่าเดียวกับแต่ละ id ที่ไม่ซ้ำกันดูสิ่งนี้อธิบายที่นี่SQL Fiddle Demo (เลื่อนลงเนื่องจากมีชุดผลลัพธ์สองชุด)

แก้ไขมีข้อผิดพลาดในการอ่านคำถามฉันจัดกลุ่มตาม id เท่านั้น แต่จำเป็นต้องมี group_contact สองรายการถ้า (ค่าจะถูกต่อกันโดยจัดกลุ่มตามชื่อและรหัสแล้วทับทั้งหมดด้วย id) คำตอบก่อนหน้านี้คือ

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

คุณสามารถดูได้ที่นี่: SQL Fiddle Demo


สิ่งนี้ไม่ได้ให้สิ่งที่บิสวาขอ
eisberg

3
ฉันคิดว่าสิ่งสำคัญคือต้องเตือนผู้คนว่าการใช้ตัวคั่นเพียงชนิดเดียวอาจทำให้เสียเปรียบได้ ฉันขอแนะนำให้สร้างตัวคั่น "ชื่อ" เป็นอัฒภาค (;) และตัวคั่นค่าสามารถคงเป็นลูกน้ำ (,)
Fandi Susanto

4
โปรดทราบว่าGROUP_CONCATอาจตัดทอนเอาต์พุตเป็นgroup_concat_max_lenไฟล์. SET group_concat_max_len=...จะช่วย แต่มันก็เป็นความคิดที่ดีต่อไปเพื่อตรวจสอบว่ากลับ (ไบต์?) group_concat_max_lenความยาวน้อยกว่า
tuomassalo

2
โปรดสังเกตด้วยว่า group_concat พบค่า NULL ค่าเดียวซึ่งจะละเว้นทั้งแถวที่มีอยู่ ผมทำงานรอบนี้ในข้อแม้ที่สองที่นี่
MatrixManAtYrService

1
หากใครประสบปัญหากับลิงค์ SQL Fiddle ที่ได้รับคำตอบ Working Fiddle อยู่ที่: sqlfiddle.com/#!9/42f994/601/0
Hitesh

21

ลอง:

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


2
ใช่ eisberg +1 คำตอบของคุณค่อนข้างถูกต้องและก่อนหน้านี้ ฉันทำผิดในคำตอบครั้งแรก
Sami

9
SELECT ID, GROUP_CONCAT(CONCAT_WS(':', NAME, VALUE) SEPARATOR ',') AS Result 
FROM test GROUP BY ID

7
คงจะดีไม่น้อยหากคุณสามารถเพิ่มคำอธิบายให้กับคำตอบของคุณได้ นี่คือข้อเสนอแนะเพื่อปรับปรุงคำตอบนี้และในอนาคต ขอบคุณ!
Luís Cruz

5

ก่อนอื่นฉันไม่เห็นเหตุผลของการมี ID ที่ไม่ซ้ำกัน แต่ฉันเดาว่าเป็น ID ที่เชื่อมต่อกับตารางอื่น ประการที่สองไม่จำเป็นต้องมีการสืบค้นย่อยซึ่งเอาชนะเซิร์ฟเวอร์ได้ คุณทำได้ในแบบสอบถามเดียวเช่นนี้

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

คุณจะได้ผลลัพธ์ที่รวดเร็วและถูกต้องและคุณสามารถแยกผลลัพธ์ตาม SEPARATOR "|" นั้นได้ ฉันใช้ตัวคั่นนี้เสมอเพราะมันเป็นไปไม่ได้ที่จะหามันในสตริงดังนั้นมันจึงไม่เหมือนใคร ไม่มีปัญหาในการมี A สองตัวคุณระบุเฉพาะค่า หรือคุณสามารถมีอีกหนึ่งคอลัมน์พร้อมตัวอักษรซึ่งจะดีกว่า แบบนี้ :

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

2
 SELECT id, GROUP_CONCAT(CONCAT_WS(':', Name, CAST(Value AS CHAR(7))) SEPARATOR ',') AS result 
    FROM test GROUP BY id

คุณต้องใช้การร่ายหรือแปลงมิฉะนั้นจะถูกส่งกลับ BLOB

ผลลัพธ์คือ

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

คุณต้องจัดการผลลัพธ์อีกครั้งโดยโปรแกรมเช่น python หรือ java


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

ชื่อตารางของฉันคือการทดสอบและสำหรับการต่อกันฉันใช้ไวยากรณ์สำหรับเส้นทาง XML ('') ฟังก์ชัน stuff จะแทรกสตริงลงในสตริงอื่น จะลบความยาวที่ระบุของอักขระในสตริงแรกที่ตำแหน่งเริ่มต้นจากนั้นแทรกสตริงที่สองลงในสตริงแรกที่ตำแหน่งเริ่มต้น

ฟังก์ชัน STUFF มีลักษณะดังนี้: STUFF (character_expression, start, length, character_expression)

character_expression คือนิพจน์ของข้อมูลอักขระ character_expression สามารถเป็นค่าคงที่ตัวแปรหรือคอลัมน์ของอักขระหรือข้อมูลไบนารี

start เป็นค่าจำนวนเต็มที่ระบุตำแหน่งที่จะเริ่มการลบและการแทรก ถ้าค่าเริ่มต้นหรือความยาวเป็นลบสตริง null จะถูกส่งกลับ ถ้า start ยาวกว่า character_expression ตัวแรกสตริง null จะถูกส่งกลับ start อาจเป็นประเภท bigint

length คือจำนวนเต็มที่ระบุจำนวนอักขระที่จะลบ ถ้าความยาวยาวกว่า character_expression ตัวแรกการลบจะเกิดขึ้นกับอักขระตัวสุดท้ายใน character_expression สุดท้าย ความยาวอาจเป็นประเภท bigint


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.