Bagaimana saya mendapatkan:
id Name Value
1 A 4
1 B 8
2 C 9
untuk
id Column
1 A:4, B:8
2 C:9
Bagaimana saya mendapatkan:
id Name Value
1 A 4
1 B 8
2 C 9
untuk
id Column
1 A:4, B:8
2 C:9
Jawaban:
Tidak diperlukan CURSOR, WHILE loop, atau Function-Defined User .
Hanya perlu berkreasi dengan FOR XML dan PATH.
[Catatan: Solusi ini hanya berfungsi pada SQL 2005 dan yang lebih baru. Pertanyaan asli tidak menentukan versi yang digunakan.]
CREATE TABLE #YourTable ([ID] INT, [Name] CHAR(1), [Value] INT)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'A',4)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'B',8)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (2,'C',9)
SELECT
[ID],
STUFF((
SELECT ', ' + [Name] + ':' + CAST([Value] AS VARCHAR(MAX))
FROM #YourTable
WHERE (ID = Results.ID)
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS NameValues
FROM #YourTable Results
GROUP BY ID
DROP TABLE #YourTable
Jika SQL Server 2017 atau SQL Server Vnext, SQL Azure Anda dapat menggunakan string_agg seperti di bawah ini:
select id, string_agg(concat(name, ':', [value]), ', ')
from #YourTable
group by id
menggunakan jalur XML tidak akan digabungkan sempurna seperti yang Anda harapkan ... itu akan menggantikan "&" dengan "& amp;" dan juga akan mengacaukan <" and ">
... mungkin beberapa hal lain, tidak yakin ... tetapi Anda dapat mencoba ini
Saya menemukan solusi untuk ini ... Anda perlu mengganti:
FOR XML PATH('')
)
dengan:
FOR XML PATH(''),TYPE
).value('(./text())[1]','VARCHAR(MAX)')
... atau NVARCHAR(MAX)
jika itu yang Anda gunakan.
kenapa sih tidak SQL
memiliki fungsi agregat gabungan? ini adalah PITA.
Aku berlari ke dalam beberapa masalah ketika saya mencoba mengkonversi saran Kevin Fairchild untuk bekerja dengan string yang mengandung spasi dan karakter XML khusus ( &
, <
, >
) yang dikodekan.
Versi terakhir dari kode saya (yang tidak menjawab pertanyaan asli tetapi mungkin bermanfaat bagi seseorang) terlihat seperti ini:
CREATE TABLE #YourTable ([ID] INT, [Name] VARCHAR(MAX), [Value] INT)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'Oranges & Lemons',4)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'1 < 2',8)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (2,'C',9)
SELECT [ID],
STUFF((
SELECT ', ' + CAST([Name] AS VARCHAR(MAX))
FROM #YourTable WHERE (ID = Results.ID)
FOR XML PATH(''),TYPE
/* Use .value to uncomment XML entities e.g. > < etc*/
).value('.','VARCHAR(MAX)')
,1,2,'') as NameValues
FROM #YourTable Results
GROUP BY ID
DROP TABLE #YourTable
Daripada menggunakan spasi sebagai pembatas dan mengganti semua spasi dengan koma, itu hanya pra-pends tanda koma dan ruang untuk setiap nilai kemudian gunakan STUFF
untuk menghapus dua karakter pertama.
Pengkodean XML dilakukan secara otomatis dengan menggunakan arahan TYPE .
Opsi lain menggunakan Sql Server 2005 dan di atasnya
---- test data
declare @t table (OUTPUTID int, SCHME varchar(10), DESCR varchar(10))
insert @t select 1125439 ,'CKT','Approved'
insert @t select 1125439 ,'RENO','Approved'
insert @t select 1134691 ,'CKT','Approved'
insert @t select 1134691 ,'RENO','Approved'
insert @t select 1134691 ,'pn','Approved'
---- actual query
;with cte(outputid,combined,rn)
as
(
select outputid, SCHME + ' ('+DESCR+')', rn=ROW_NUMBER() over (PARTITION by outputid order by schme, descr)
from @t
)
,cte2(outputid,finalstatus,rn)
as
(
select OUTPUTID, convert(varchar(max),combined), 1 from cte where rn=1
union all
select cte2.outputid, convert(varchar(max),cte2.finalstatus+', '+cte.combined), cte2.rn+1
from cte2
inner join cte on cte.OUTPUTID = cte2.outputid and cte.rn=cte2.rn+1
)
select outputid, MAX(finalstatus) from cte2 group by outputid
Instal Agregat SQLCLR dari http://groupconcat.codeplex.com
Kemudian Anda dapat menulis kode seperti ini untuk mendapatkan hasil yang Anda minta:
CREATE TABLE foo
(
id INT,
name CHAR(1),
Value CHAR(1)
);
INSERT INTO dbo.foo
(id, name, Value)
VALUES (1, 'A', '4'),
(1, 'B', '8'),
(2, 'C', '9');
SELECT id,
dbo.GROUP_CONCAT(name + ':' + Value) AS [Column]
FROM dbo.foo
GROUP BY id;
SQL Server 2005 dan yang lebih baru memungkinkan Anda untuk membuat fungsi agregat kustom Anda sendiri , termasuk untuk hal-hal seperti penggabungan - lihat contoh di bagian bawah artikel yang ditautkan.
Delapan tahun kemudian ... Mesin Database Microsoft SQL Server vNext akhirnya meningkatkan Transact-SQL untuk secara langsung mendukung penggabungan string yang dikelompokkan. Komunitas Technical Preview versi 1.0 menambahkan fungsi STRING_AGG dan CTP 1.1 menambahkan klausa WITHIN GROUP untuk fungsi STRING_AGG.
Referensi: https://msdn.microsoft.com/en-us/library/mt775028.aspx
Ini hanya tambahan untuk posting Kevin Fairchild (sangat pintar). Saya ingin menambahkannya sebagai komentar, tetapi saya belum memiliki poin yang cukup :)
Saya menggunakan ide ini untuk tampilan yang sedang saya kerjakan, namun item yang saya gabungkan mengandung ruang. Jadi saya memodifikasi sedikit kode untuk tidak menggunakan spasi sebagai pembatas.
Sekali lagi terima kasih atas solusi kerennya Kevin!
CREATE TABLE #YourTable ( [ID] INT, [Name] CHAR(1), [Value] INT )
INSERT INTO #YourTable ([ID], [Name], [Value]) VALUES (1, 'A', 4)
INSERT INTO #YourTable ([ID], [Name], [Value]) VALUES (1, 'B', 8)
INSERT INTO #YourTable ([ID], [Name], [Value]) VALUES (2, 'C', 9)
SELECT [ID],
REPLACE(REPLACE(REPLACE(
(SELECT [Name] + ':' + CAST([Value] AS VARCHAR(MAX)) as A
FROM #YourTable
WHERE ( ID = Results.ID )
FOR XML PATH (''))
, '</A><A>', ', ')
,'<A>','')
,'</A>','') AS NameValues
FROM #YourTable Results
GROUP BY ID
DROP TABLE #YourTable
Di Oracle Anda dapat menggunakan fungsi agregat LISTAGG.
Catatan asli
name type
------------
name1 type1
name2 type2
name2 type3
Sql
SELECT name, LISTAGG(type, '; ') WITHIN GROUP(ORDER BY name)
FROM table
GROUP BY name
Hasil dalam
name type
------------
name1 type1
name2 type2; type3
Pertanyaan semacam ini sering ditanyakan di sini, dan solusinya akan sangat bergantung pada persyaratan yang mendasarinya:
https://stackoverflow.com/search?q=sql+pivot
dan
https://stackoverflow.com/search?q=sql+concatenate
Biasanya, tidak ada cara hanya SQL untuk melakukan ini tanpa sql dinamis, fungsi yang ditentukan pengguna, atau kursor.
Hanya untuk menambah apa yang dikatakan Cade, ini biasanya tampilan depan dan karenanya harus ditangani di sana. Saya tahu bahwa kadang-kadang lebih mudah untuk menulis sesuatu 100% dalam SQL untuk hal-hal seperti ekspor file atau solusi "SQL saja" lainnya, tetapi sebagian besar waktu penggabungan ini harus ditangani di lapisan tampilan Anda.
Tidak perlu kursor ... loop sementara sudah cukup.
------------------------------
-- Setup
------------------------------
DECLARE @Source TABLE
(
id int,
Name varchar(30),
Value int
)
DECLARE @Target TABLE
(
id int,
Result varchar(max)
)
INSERT INTO @Source(id, Name, Value) SELECT 1, 'A', 4
INSERT INTO @Source(id, Name, Value) SELECT 1, 'B', 8
INSERT INTO @Source(id, Name, Value) SELECT 2, 'C', 9
------------------------------
-- Technique
------------------------------
INSERT INTO @Target (id)
SELECT id
FROM @Source
GROUP BY id
DECLARE @id int, @Result varchar(max)
SET @id = (SELECT MIN(id) FROM @Target)
WHILE @id is not null
BEGIN
SET @Result = null
SELECT @Result =
CASE
WHEN @Result is null
THEN ''
ELSE @Result + ', '
END + s.Name + ':' + convert(varchar(30),s.Value)
FROM @Source s
WHERE id = @id
UPDATE @Target
SET Result = @Result
WHERE id = @id
SET @id = (SELECT MIN(id) FROM @Target WHERE @id < id)
END
SELECT *
FROM @Target
Mari kita menjadi sangat sederhana:
SELECT stuff(
(
select ', ' + x from (SELECT 'xxx' x union select 'yyyy') tb
FOR XML PATH('')
)
, 1, 2, '')
Ganti baris ini:
select ', ' + x from (SELECT 'xxx' x union select 'yyyy') tb
Dengan kueri Anda.
tidak melihat jawaban lintas diterapkan, juga tidak perlu ekstraksi xml. Ini adalah versi yang sedikit berbeda dari apa yang ditulis Kevin Fairchild. Lebih cepat dan lebih mudah digunakan dalam permintaan yang lebih kompleks:
select T.ID
,MAX(X.cl) NameValues
from #YourTable T
CROSS APPLY
(select STUFF((
SELECT ', ' + [Name] + ':' + CAST([Value] AS VARCHAR(MAX))
FROM #YourTable
WHERE (ID = T.ID)
FOR XML PATH(''))
,1,2,'') [cl]) X
GROUP BY T.ID
Anda dapat meningkatkan kinerja yang signifikan dengan cara berikut jika grup dengan sebagian besar berisi satu item:
SELECT
[ID],
CASE WHEN MAX( [Name]) = MIN( [Name]) THEN
MAX( [Name]) NameValues
ELSE
STUFF((
SELECT ', ' + [Name] + ':' + CAST([Value] AS VARCHAR(MAX))
FROM #YourTable
WHERE (ID = Results.ID)
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS NameValues
END
FROM #YourTable Results
GROUP BY ID
Menggunakan Ganti Fungsi dan UNTUK PATUNG JSON
SELECT T3.DEPT, REPLACE(REPLACE(T3.ENAME,'{"ENAME":"',''),'"}','') AS ENAME_LIST
FROM (
SELECT DEPT, (SELECT ENAME AS [ENAME]
FROM EMPLOYEE T2
WHERE T2.DEPT=T1.DEPT
FOR JSON PATH,WITHOUT_ARRAY_WRAPPER) ENAME
FROM EMPLOYEE T1
GROUP BY DEPT) T3
Untuk sampel data dan lebih banyak cara klik di sini
Jika Anda telah mengaktifkan CLR Anda bisa menggunakan pustaka Group_Concat dari GitHub
GROUP_CONCAT()
fungsi agregatnya, tetapi menyelesaikannya pada Microsoft SQL Server lebih canggung. Lihat pertanyaan SO berikut untuk mendapatkan bantuan: " Bagaimana cara mendapatkan beberapa catatan terhadap satu catatan berdasarkan hubungan? "