พิจารณาชื่อตารางการถือครองฐานข้อมูลที่มีสามแถว:
Peter
Paul
Mary
มีวิธีง่าย ๆ ในการเปลี่ยนให้เป็นสตริงเดียวPeter, Paul, Mary
หรือไม่?
พิจารณาชื่อตารางการถือครองฐานข้อมูลที่มีสามแถว:
Peter
Paul
Mary
มีวิธีง่าย ๆ ในการเปลี่ยนให้เป็นสตริงเดียวPeter, Paul, Mary
หรือไม่?
คำตอบ:
ถ้าคุณอยู่ใน SQL Server 2017 หรือ Azure ดูคำตอบ Mathieu Renda
ฉันมีปัญหาที่คล้ายกันเมื่อฉันพยายามเข้าร่วมสองตารางที่มีความสัมพันธ์แบบหนึ่งต่อหลายคน ใน SQL 2005 ฉันพบว่าXML PATH
วิธีนี้สามารถจัดการการต่อแถวได้ง่ายมาก
หากมีตารางเรียกว่า STUDENTS
SubjectID StudentName
---------- -------------
1 Mary
1 John
1 Sam
2 Alaina
2 Edward
ผลลัพธ์ที่ฉันคาดไว้คือ:
SubjectID StudentName
---------- -------------
1 Mary, John, Sam
2 Alaina, Edward
ฉันใช้สิ่งต่อไปนี้T-SQL
:
SELECT Main.SubjectID,
LEFT(Main.Students,Len(Main.Students)-1) As "Students"
FROM
(
SELECT DISTINCT ST2.SubjectID,
(
SELECT ST1.StudentName + ',' AS [text()]
FROM dbo.Students ST1
WHERE ST1.SubjectID = ST2.SubjectID
ORDER BY ST1.SubjectID
FOR XML PATH ('')
) [Students]
FROM dbo.Students ST2
) [Main]
คุณสามารถทำสิ่งเดียวกันด้วยวิธีที่กะทัดรัดกว่านี้ถ้าคุณสามารถต่อคอมม่าที่จุดเริ่มต้นและใช้substring
ข้ามสิ่งแรกดังนั้นคุณไม่จำเป็นต้องทำแบบสอบถามย่อย:
SELECT DISTINCT ST2.SubjectID,
SUBSTRING(
(
SELECT ','+ST1.StudentName AS [text()]
FROM dbo.Students ST1
WHERE ST1.SubjectID = ST2.SubjectID
ORDER BY ST1.SubjectID
FOR XML PATH ('')
), 2, 1000) [Students]
FROM dbo.Students ST2
<
&
ดูความคิดเห็นของ @ BenHinman
FOR XML PATH ('')
วิธีการนี้สามารถพึ่งพาพฤติกรรมที่ไม่มีเอกสารของ ซึ่งหมายความว่าไม่ควรพิจารณาว่าเชื่อถือได้เนื่องจากแพตช์หรืออัปเดตใด ๆ อาจเปลี่ยนแปลงวิธีการทำงานของฟังก์ชั่นนี้ โดยพื้นฐานแล้วมันขึ้นอยู่กับคุณสมบัติที่ไม่รองรับ
FOR XML
มีไว้เพื่อสร้าง XML โดยไม่ต่อสายอักขระตามอำเภอใจ นั่นเป็นเหตุผลที่มันหนี &
, <
และ>
รหัสนิติบุคคล XML ( &
, <
, >
) ฉันคิดว่ามันจะหลบหนี"
และ'
ไปที่"
และ'
ในคุณสมบัติเช่นกัน มันไม่ได้ GROUP_CONCAT()
, string_agg()
, array_agg()
, listagg()
ฯลฯ แม้ว่าคุณสามารถชนิดของการทำให้มันทำอย่างนั้น เราควรใช้เวลาในการเรียกร้องให้ Microsoft ใช้ฟังก์ชั่นที่เหมาะสม
string_agg
ใน v.Next และทั้งหมดนี้สามารถหายไปได้
คำตอบนี้อาจส่งคืนผลลัพธ์ที่ไม่คาดคิดเพื่อให้ได้ผลลัพธ์ที่สอดคล้องกันให้ใช้วิธีการอย่างใดอย่างหนึ่งของ FOR XML PATH ที่มีรายละเอียดในคำตอบอื่น ๆ
ใช้COALESCE
:
DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(@Names + ', ', '') + Name
FROM People
เพียงคำอธิบาย (เนื่องจากคำตอบนี้ดูเหมือนจะได้รับมุมมองที่ค่อนข้างปกติ):
1) ไม่จำเป็นต้องเริ่มต้น@Names
ด้วยค่าสตริงว่าง
2) ไม่จำเป็นต้องถอดตัวคั่นพิเศษออกในตอนท้าย
@Names
เป็นโมฆะหลังจากแถวนั้นและแถวถัดไปจะเริ่มต้นมาเป็นสตริงที่ว่างเปล่าอีกครั้ง. แก้ไขได้อย่างง่ายดายด้วยการเป็นหนึ่งในสอง การแก้ปัญหา:DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(@Names + ', ', '') + Name
FROM People
WHERE Name IS NOT NULL
หรือ:
DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(@Names + ', ', '') +
ISNULL(Name, 'N/A')
FROM People
ขึ้นอยู่กับพฤติกรรมที่คุณต้องการ (ตัวเลือกแรกเพียงกรองNULLออกตัวเลือกที่สองเก็บไว้ในรายการด้วยข้อความทำเครื่องหมาย [แทนที่ 'N / A' ด้วยสิ่งที่เหมาะสมสำหรับคุณ])
เริ่มต้นด้วย SQL Server เวอร์ชั่นถัดไปในที่สุดเราก็สามารถเชื่อมโยงข้ามแถวได้โดยไม่ต้องเปลี่ยนไปใช้ตัวแปรหรือ XML ของคาถา
โดยไม่ต้องจัดกลุ่ม
SELECT STRING_AGG(Name, ', ') AS Departments
FROM HumanResources.Department;
ด้วยการจัดกลุ่ม:
SELECT GroupName, STRING_AGG(Name, ', ') AS Departments
FROM HumanResources.Department
GROUP BY GroupName;
ด้วยการจัดกลุ่มและการจัดเรียงย่อย
SELECT GroupName, STRING_AGG(Name, ', ') WITHIN GROUP (ORDER BY Name ASC) AS Departments
FROM HumanResources.Department
GROUP BY GroupName;
วิธีหนึ่งที่ยังไม่แสดงผ่านXML
data()
คำสั่งใน MS SQL Server คือ:
สมมติว่าตารางชื่อ NameList โดยมีหนึ่งคอลัมน์ชื่อ FName
SELECT FName + ', ' AS 'data()'
FROM NameList
FOR XML PATH('')
ผลตอบแทน:
"Peter, Paul, Mary, "
ต้องดำเนินการเฉพาะเครื่องหมายจุลภาคพิเศษเท่านั้น
แก้ไข:ตามที่นำมาจากความคิดเห็นของ @ NReilingh คุณสามารถใช้วิธีการต่อไปนี้เพื่อลบเครื่องหมายจุลภาคต่อท้าย สมมติว่าชื่อตารางและคอลัมน์เดียวกัน:
STUFF(REPLACE((SELECT '#!' + LTRIM(RTRIM(FName)) AS 'data()' FROM NameList
FOR XML PATH('')),' #!',', '), 1, 2, '') as Brands
+ ', '
มันก็ยังเพิ่มช่องว่างเดียวระหว่างองค์ประกอบที่ตัดแบ่งทั้งหมด
SELECT STUFF(REPLACE((SELECT '#!'+city AS 'data()' FROM #cityzip FOR XML PATH ('')),' #!',', '),1,2,'')
SELECT Stuff(
(SELECT N', ' + Name FROM Names FOR XML PATH(''),TYPE)
.value('text()[1]','nvarchar(max)'),1,2,N'')
คุณสามารถใช้ไวยากรณ์ FOR JSON
กล่าวคือ
SELECT per.ID,
Emails = JSON_VALUE(
REPLACE(
(SELECT _ = em.Email FROM Email em WHERE em.Person = per.ID FOR JSON PATH)
,'"},{"_":"',', '),'$[0]._'
)
FROM Person per
และผลลัพธ์จะกลายเป็น
Id Emails
1 abc@gmail.com
2 NULL
3 def@gmail.com, xyz@gmail.com
สิ่งนี้จะใช้ได้แม้ข้อมูลของคุณจะมีอักขระ XML ที่ไม่ถูกต้อง
'"},{"_":"'
มีความปลอดภัยเพราะถ้าข้อมูลที่คุณมี'"},{"_":"',
มันจะหนีไป"},{\"_\":\"
คุณสามารถแทนที่', '
ด้วยตัวคั่นสตริงใด ๆ
คุณสามารถใช้ฟังก์ชัน STRING_AGGใหม่
<
, >
, &
ฯลฯ ซึ่งFOR XML PATH('')
จะหลบหนีโดยอัตโนมัติ
ใน MySQL มีฟังก์ชั่นGROUP_CONCAT ()ซึ่งช่วยให้คุณสามารถเชื่อมค่าจากหลายแถวเข้าด้วยกัน ตัวอย่าง:
SELECT 1 AS a, GROUP_CONCAT(name ORDER BY name ASC SEPARATOR ', ') AS people
FROM users
WHERE id IN (1,2,3)
GROUP BY a
SEPARATOR '", "'
ฉันจะพลาดบางตัวอักษรในตอนท้ายของรายการสุดท้าย ทำไมสิ่งนี้ถึงเกิดขึ้นได้?
CHAR
, คุณต้องส่งมันเช่นผ่านทางGROUP_CONCAT( CAST(id AS CHAR(8)) ORDER BY id ASC SEPARATOR ',')
2) หากคุณมีค่ามากมายที่เข้ามาคุณควรเพิ่มgroup_concat_max_len
ตามที่เขียนไว้ในstackoverflow.com/a/1278210/1498405
ใช้COALESCE - เรียนรู้เพิ่มเติมจากที่นี่
ตัวอย่างเช่น
102
103
104
จากนั้นเขียนรหัสด้านล่างในเซิร์ฟเวอร์ sql
Declare @Numbers AS Nvarchar(MAX) -- It must not be MAX if you have few numbers
SELECT @Numbers = COALESCE(@Numbers + ',', '') + Number
FROM TableName where Number IS NOT NULL
SELECT @Numbers
ผลผลิตจะเป็น:
102,103,104
Declare @Numbers AS Nvarchar(MAX)
และมันก็ใช้ได้ดี คุณช่วยอธิบายได้ไหมว่าทำไมคุณถึงไม่แนะนำให้ใช้
อาร์เรย์ Postgres ยอดเยี่ยม ตัวอย่าง:
สร้างข้อมูลทดสอบ:
postgres=# \c test
You are now connected to database "test" as user "hgimenez".
test=# create table names (name text);
CREATE TABLE
test=# insert into names (name) values ('Peter'), ('Paul'), ('Mary');
INSERT 0 3
test=# select * from names;
name
-------
Peter
Paul
Mary
(3 rows)
รวมไว้ในอาร์เรย์:
test=# select array_agg(name) from names;
array_agg
-------------------
{Peter,Paul,Mary}
(1 row)
แปลงอาร์เรย์เป็นสตริงที่คั่นด้วยเครื่องหมายจุลภาค:
test=# select array_to_string(array_agg(name), ', ') from names;
array_to_string
-------------------
Peter, Paul, Mary
(1 row)
DONE
select array_to_string(array_agg(name||'('||id||')'
Oracle 11g รีลีส 2 รองรับฟังก์ชั่น LISTAGG เอกสารที่นี่
COLUMN employees FORMAT A50
SELECT deptno, LISTAGG(ename, ',') WITHIN GROUP (ORDER BY ename) AS employees
FROM emp
GROUP BY deptno;
DEPTNO EMPLOYEES
---------- --------------------------------------------------
10 CLARK,KING,MILLER
20 ADAMS,FORD,JONES,SCOTT,SMITH
30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD
3 rows selected.
ใช้ความระมัดระวังในการใช้ฟังก์ชั่นนี้หากมีความเป็นไปได้ที่สตริงผลลัพธ์จะมีความยาวเกิน 4,000 อักขระ มันจะโยนข้อยกเว้น หากเป็นกรณีนี้คุณต้องจัดการกับข้อยกเว้นหรือหมุนฟังก์ชั่นของคุณเองที่ป้องกันไม่ให้สตริงที่เข้าร่วมไปเกิน 4,000 ตัวอักษร
LISTAGG
ทำงานได้สมบูรณ์แบบ! เพียงอ่านเอกสารที่ลิงก์ไว้ที่นี่ wm_concat
ลบออกจากรุ่น 12c เป็นต้นไป
ใน SQL Server 2005 และใหม่กว่าใช้แบบสอบถามด้านล่างเพื่อต่อแถว
DECLARE @t table
(
Id int,
Name varchar(10)
)
INSERT INTO @t
SELECT 1,'a' UNION ALL
SELECT 1,'b' UNION ALL
SELECT 2,'c' UNION ALL
SELECT 2,'d'
SELECT ID,
stuff(
(
SELECT ','+ [Name] FROM @t WHERE Id = t.Id FOR XML PATH('')
),1,1,'')
FROM (SELECT DISTINCT ID FROM @t ) t
<
&
ฉันไม่มีสิทธิ์เข้าถึง SQL Server ที่บ้านดังนั้นฉันเดาว่าที่นี่ แต่มันมากหรือน้อย:
DECLARE @names VARCHAR(500)
SELECT @names = @names + ' ' + Name
FROM Names
SELECT @names = @names + CASE WHEN LEN(@names)=0 THEN '' ELSE ' ' END + Name FROM Names
SELECT @names = @names + ISNULL(' ' + Name, '')
แนะนำให้ใช้โซลูชัน CTE แบบเรียกซ้ำ แต่ไม่มีรหัสให้ รหัสด้านล่างเป็นตัวอย่างของ CTE แบบเรียกซ้ำ ทราบว่าแม้ว่าผลลัพธ์ที่ตรงกับคำถามที่ว่าข้อมูลไม่ค่อนข้างตรงกับคำอธิบายที่ได้รับในขณะที่ฉันคิดว่าคุณอยากจะทำเช่นนี้ที่กลุ่มของแถวไม่ได้ทุกแถวในตาราง การเปลี่ยนเพื่อให้ตรงกับแถวทั้งหมดในตารางจะถูกทิ้งไว้เป็นแบบฝึกหัดสำหรับผู้อ่าน
;WITH basetable AS (
SELECT
id,
CAST(name AS VARCHAR(MAX)) name,
ROW_NUMBER() OVER (Partition BY id ORDER BY seq) rw,
COUNT(*) OVER (Partition BY id) recs
FROM (VALUES
(1, 'Johnny', 1),
(1, 'M', 2),
(2, 'Bill', 1),
(2, 'S.', 4),
(2, 'Preston', 5),
(2, 'Esq.', 6),
(3, 'Ted', 1),
(3, 'Theodore', 2),
(3, 'Logan', 3),
(4, 'Peter', 1),
(4, 'Paul', 2),
(4, 'Mary', 3)
) g (id, name, seq)
),
rCTE AS (
SELECT recs, id, name, rw
FROM basetable
WHERE rw = 1
UNION ALL
SELECT b.recs, r.ID, r.name +', '+ b.name name, r.rw + 1
FROM basetable b
INNER JOIN rCTE r ON b.id = r.id AND b.rw = r.rw + 1
)
SELECT name
FROM rCTE
WHERE recs = rw AND ID=4
name
คอลัมน์ลงในสตริงคั่นด้วยเครื่องหมายจุลภาค 4 กลุ่มของid
s ฉันคิดว่านี่เป็นงานมากกว่าโซลูชันอื่น ๆ ส่วนใหญ่สำหรับ SQL Server
คุณต้องสร้างตัวแปรที่จะเก็บผลลัพธ์สุดท้ายของคุณและเลือกไว้เช่นนั้น
DECLARE @char VARCHAR(MAX);
SELECT @char = COALESCE(@char + ', ' + [column], [column])
FROM [table];
PRINT @char;
เริ่มต้นด้วย PostgreSQL 9.0 ซึ่งค่อนข้างง่าย:
select string_agg(name, ',')
from names;
ในรุ่นก่อน 9.0 array_agg()
สามารถใช้งานได้ตามที่แสดงโดย hgmnz
SELECT string_agg(non_text_type::text, ',') FROM table
varchar
หรือchar
ใน SQL Server v ถัดไปสิ่งนี้จะถูกสร้างขึ้นด้วยฟังก์ชัน STRING_AGG อ่านเพิ่มเติมเกี่ยวกับที่นี่: https://msdn.microsoft.com/en-us/library/mt790580.aspx
การใช้ XML ช่วยให้ฉันสามารถแยกแถวด้วยเครื่องหมายจุลภาคได้ สำหรับเครื่องหมายจุลภาคพิเศษเราสามารถใช้ฟังก์ชั่นแทนที่ของ SQL Server แทนที่จะเพิ่มเครื่องหมายจุลภาคการใช้ AS 'data ()' จะต่อแถวกับช่องว่างซึ่งภายหลังสามารถแทนที่ด้วยเครื่องหมายจุลภาคเป็นไวยากรณ์ที่เขียนด้านล่าง
REPLACE(
(select FName AS 'data()' from NameList for xml path(''))
, ' ', ', ')
โซลูชันที่พร้อมใช้งานโดยไม่มีเครื่องหมายจุลภาคพิเศษ:
select substring(
(select ', '+Name AS 'data()' from Names for xml path(''))
,3, 255) as "MyList"
รายการว่างจะส่งผลให้ค่า NULL โดยปกติคุณจะแทรกรายการลงในคอลัมน์ตารางหรือตัวแปรโปรแกรม: ปรับความยาวสูงสุด 255 ความต้องการของคุณ
(Diwakar และ Jens Frandsen ให้คำตอบที่ดี แต่ต้องการการปรับปรุง)
', '
ด้วย','
ถ้าคุณไม่ต้องการพื้นที่เพิ่ม
SELECT STUFF((SELECT ', ' + name FROM [table] FOR XML PATH('')), 1, 2, '')
นี่คือตัวอย่าง:
DECLARE @t TABLE (name VARCHAR(10))
INSERT INTO @t VALUES ('Peter'), ('Paul'), ('Mary')
SELECT STUFF((SELECT ', ' + name FROM @t FOR XML PATH('')), 1, 2, '')
--Peter, Paul, Mary
DECLARE @Names VARCHAR(8000)
SELECT @name = ''
SELECT @Names = @Names + ',' + Names FROM People
SELECT SUBSTRING(2, @Names, 7998)
สิ่งนี้ทำให้จุลภาคหลงทางที่จุดเริ่มต้น
อย่างไรก็ตามหากคุณต้องการคอลัมน์อื่น ๆ หรือเป็นตารางลูกคุณจะต้องล้อมรอบคอลัมน์นี้ในฟิลด์ผู้ใช้กำหนดสเกลาร์ (UDF)
คุณสามารถใช้เส้นทาง XML เป็นแบบสอบถามย่อยที่มีความสัมพันธ์ในส่วนคำสั่ง SELECT ได้เช่นกัน (แต่ฉันต้องรอจนกว่าฉันจะกลับไปทำงานเพราะ Google ไม่ทำงานที่บ้าน :-)
ด้วยคำตอบอื่น ๆ ผู้ที่อ่านคำตอบจะต้องทราบถึงตารางโดเมนที่เฉพาะเจาะจงเช่นยานพาหนะหรือนักเรียน ตารางจะต้องสร้างและเติมด้วยข้อมูลเพื่อทดสอบวิธีแก้ปัญหา
ด้านล่างเป็นตัวอย่างที่ใช้ตาราง "Information_Schema.Columns" ของ SQL Server ด้วยการใช้โซลูชันนี้ไม่จำเป็นต้องสร้างตารางหรือเพิ่มข้อมูล ตัวอย่างนี้สร้างรายการชื่อคอลัมน์ที่คั่นด้วยเครื่องหมายจุลภาคสำหรับตารางทั้งหมดในฐานข้อมูล
SELECT
Table_Name
,STUFF((
SELECT ',' + Column_Name
FROM INFORMATION_SCHEMA.Columns Columns
WHERE Tables.Table_Name = Columns.Table_Name
ORDER BY Column_Name
FOR XML PATH ('')), 1, 1, ''
)Columns
FROM INFORMATION_SCHEMA.Columns Tables
GROUP BY TABLE_NAME
สำหรับ Oracle DB ให้ดูที่คำถามนี้: การผสานหลายแถวเข้าใน Oracle ได้อย่างไรโดยไม่ต้องสร้างโพรซีเดอร์ที่เก็บไว้?
คำตอบที่ดีที่สุดคือ @Emmanuel โดยใช้ฟังก์ชัน LISTAGG () ในตัวซึ่งมีอยู่ใน Oracle 11g รีลีส 2 และใหม่กว่า
SELECT question_id,
LISTAGG(element_id, ',') WITHIN GROUP (ORDER BY element_id)
FROM YOUR_TABLE;
GROUP BY question_id
ตามที่ @ user762952 ชี้ให้เห็นและตามเอกสารของออราเคิลhttp://www.oracle-base.com/articles/misc/string-aggregation-techniques.phpฟังก์ชั่น WM_CONCAT () ก็เป็นตัวเลือกเช่นกัน ดูเหมือนว่าจะมีความเสถียร แต่ Oracle แนะนำอย่างชัดเจนให้ใช้กับแอพพลิเคชั่น SQL ใด ๆ ดังนั้นให้ใช้ความเสี่ยงของคุณเอง
นอกจากนั้นคุณจะต้องเขียนฟังก์ชั่นของคุณเอง เอกสาร Oracle ข้างต้นมีคำแนะนำเกี่ยวกับวิธีการทำเช่นนั้น
เพื่อหลีกเลี่ยงค่าว่างคุณสามารถใช้ CONCAT ()
DECLARE @names VARCHAR(500)
SELECT @names = CONCAT(@names, ' ', name)
FROM Names
select @names
ฉันชอบความงดงามของมันคำตอบของ Dana แค่อยากทำให้มันสมบูรณ์
DECLARE @names VARCHAR(MAX)
SET @names = ''
SELECT @names = @names + ', ' + Name FROM Names
-- Deleting last two symbols (', ')
SET @sSql = LEFT(@sSql, LEN(@sSql) - 1)
SELECT @names = @names + CASE WHEN LEN(@names)=0 THEN '' ELSE ', ' END + Name FROM Names
แล้วคุณไม่ต้องตัดทอนหลังจากนั้น
คำตอบนี้จะต้องใช้สิทธิ์พิเศษในเซิร์ฟเวอร์ในการทำงาน
แอสเซมบลีเป็นตัวเลือกที่ดีสำหรับคุณ มีเว็บไซต์จำนวนมากที่อธิบายถึงวิธีการสร้าง อย่างใดอย่างหนึ่งที่ผมคิดว่าจะมีการอธิบายอย่างดีนี้เป็นหนึ่งใน
ถ้าคุณต้องการฉันได้สร้างชุดประกอบขึ้นมาและสามารถดาวน์โหลด DLL ได้ที่นี่ที่นี่
เมื่อคุณดาวน์โหลดแล้วคุณจะต้องเรียกใช้สคริปต์ต่อไปนี้ใน SQL Server ของคุณ:
CREATE Assembly concat_assembly
AUTHORIZATION dbo
FROM '<PATH TO Concat.dll IN SERVER>'
WITH PERMISSION_SET = SAFE;
GO
CREATE AGGREGATE dbo.concat (
@Value NVARCHAR(MAX)
, @Delimiter NVARCHAR(4000)
) RETURNS NVARCHAR(MAX)
EXTERNAL Name concat_assembly.[Concat.Concat];
GO
sp_configure 'clr enabled', 1;
RECONFIGURE
สังเกตว่าเส้นทางไปยังแอสเซมบลีอาจเข้าถึงเซิร์ฟเวอร์ได้ เนื่องจากคุณทำตามขั้นตอนทั้งหมดเรียบร้อยแล้วคุณสามารถใช้ฟังก์ชันดังนี้:
SELECT dbo.Concat(field1, ',')
FROM Table1
หวังว่ามันจะช่วย !!!
ตัวอย่าง MySQL ที่สมบูรณ์:
เรามีผู้ใช้ที่สามารถมีข้อมูลจำนวนมากและเราต้องการที่จะมีผลลัพธ์ที่เราสามารถเห็นผู้ใช้ทั้งหมดในรายการ:
ผลลัพธ์:
___________________________
| id | rowList |
|-------------------------|
| 0 | 6, 9 |
| 1 | 1,2,3,4,5,7,8,1 |
|_________________________|
การตั้งค่าตาราง:
CREATE TABLE `Data` (
`id` int(11) NOT NULL,
`user_id` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=latin1;
INSERT INTO `Data` (`id`, `user_id`) VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 1),
(5, 1),
(6, 0),
(7, 1),
(8, 1),
(9, 0),
(10, 1);
CREATE TABLE `User` (
`id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `User` (`id`) VALUES
(0),
(1);
ค้นหา:
SELECT User.id, GROUP_CONCAT(Data.id ORDER BY Data.id) AS rowList FROM User LEFT JOIN Data ON User.id = Data.user_id GROUP BY User.id
ฉันมักจะใช้ select เช่นนี้เพื่อเชื่อมสตริงใน SQL Server:
with lines as
(
select
row_number() over(order by id) id, -- id is a line id
line -- line of text.
from
source -- line source
),
result_lines as
(
select
id,
cast(line as nvarchar(max)) line
from
lines
where
id = 1
union all
select
l.id,
cast(r.line + N', ' + l.line as nvarchar(max))
from
lines l
inner join
result_lines r
on
l.id = r.id + 1
)
select top 1
line
from
result_lines
order by
id desc
หากคุณต้องการจัดการกับโมฆะคุณสามารถทำได้โดยการเพิ่มส่วนคำสั่งที่หรือเพิ่มอีก COALESCE รอบแรก
DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(COALESCE(@Names + ', ', '') + Name, @Names) FROM People
สิ่งนี้ใช้ได้สำหรับฉัน ( SqlServer 2016 ):
SELECT CarNamesString = STUFF((
SELECT ',' + [Name]
FROM tbl_cars
FOR XML PATH('')
), 1, 1, '')
นี่คือแหล่งที่มา: https://www.mytecbits.com/
และทางออกสำหรับMySql (เนื่องจากหน้านี้แสดงใน Google สำหรับ MySql)
SELECT [Name],
GROUP_CONCAT(DISTINCT [Name] SEPARATOR ',')
FROM tbl_cars
จากเอกสาร MySql
ใน Oracle wm_concat
มันเป็น ฉันเชื่อว่าฟังก์ชั่นนี้มีในรุ่น 10gขึ้นไป
สิ่งนี้มีประโยชน์เช่นกัน
create table #test (id int,name varchar(10))
--use separate inserts on older versions of SQL Server
insert into #test values (1,'Peter'), (1,'Paul'), (1,'Mary'), (2,'Alex'), (3,'Jack')
DECLARE @t VARCHAR(255)
SELECT @t = ISNULL(@t + ',' + name, name) FROM #test WHERE id = 1
select @t
drop table #test
ผลตอบแทน
Peter,Paul,Mary