Nasıl alabilirim:
id Name Value
1 A 4
1 B 8
2 C 9
için
id Column
1 A:4, B:8
2 C:9
Nasıl alabilirim:
id Name Value
1 A 4
1 B 8
2 C 9
için
id Column
1 A:4, B:8
2 C:9
Yanıtlar:
CURSOR, WHILE döngüsü veya Kullanıcı Tanımlı İşlev gerekmez .
FOR XML ve PATH ile yaratıcı olmanız yeterlidir.
[Not: Bu çözüm yalnızca SQL 2005 ve sonraki sürümlerinde çalışır. Orijinal soru kullanılan sürümü belirtmedi.]
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
SQL Server 2017 veya SQL Server Vnext, SQL Azure ise string_agg'yi aşağıdaki gibi kullanabilirsiniz:
select id, string_agg(concat(name, ':', [value]), ', ')
from #YourTable
group by id
XML yolunu kullanmak beklediğiniz gibi mükemmel bir şekilde birleştirilmez ... "&" yerine "& amp;" ve aynı zamanda<" and ">
... belki başka birkaç şeyle uğraşacak, emin değilim ... ama bunu deneyebilirsiniz
Bunun için bir çözüm buldum ... değiştirmeniz gerekiyor:
FOR XML PATH('')
)
ile:
FOR XML PATH(''),TYPE
).value('(./text())[1]','VARCHAR(MAX)')
...veya NVARCHAR(MAX)
da kullandığın şey buysa.
neden cehennemde SQL
birleştirilmiş bir toplama işlevi yok? Bu bir PITA.
Ben Boşluk içeren dizeleri ve özel XML karakterleri (çalışmak Kevin Fairchild'ın öneri dönüştürme çalıştığında sorunların bir çift koştu &
, <
,>
kodlanmış edildi).
Kodumun son sürümü (orijinal soruya cevap vermeyen, ancak birileri için yararlı olabilir) şöyle görünür:
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
Bir alanı sınırlayıcı olarak kullanmak ve tüm boşlukları virgülle değiştirmek yerine, her değere bir virgül ve boşluk ekler. STUFF
ilk iki karakteri kaldırmak için .
XML kodlaması, TYPE yönergesi kullanılarak otomatik olarak halledilir .
Sql Server 2005 ve sonraki sürümlerini kullanan başka bir seçenek
---- 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
SQLCLR Agregalarını http://groupconcat.codeplex.com adresinden yükleyin.
Sonra istediğiniz sonucu almak için böyle bir kod yazabilirsiniz:
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 ve sonraki sürümler , birleştirme gibi şeyler de dahil olmak üzere kendi özel toplama işlevlerinizi oluşturmanıza izin verir . Bağlantılı makalenin altındaki örneğe bakın.
Sekiz yıl sonra ... Microsoft SQL Server vNext Veritabanı Altyapısı nihayet Transact-SQL'i gruplandırılmış dize birleştirmeyi doğrudan destekleyecek şekilde geliştirdi. Topluluk Teknik Önizleme sürüm 1.0, STRING_AGG işlevini ve CTP 1.1, STRING_AGG işlevi için WITHIN GROUP yan tümcesini ekledi.
Referans: https://msdn.microsoft.com/en-us/library/mt775028.aspx
Bu, Kevin Fairchild'in gönderisine sadece bir ektir (bu arada çok zekice). Yorum olarak eklerdim, ama henüz yeterli puanım yok :)
Bu fikri üzerinde çalıştığım bir görüş için kullanıyordum, ancak bir araya getirdiğim öğeler boşluk içeriyordu. Bu yüzden boşlukları sınırlayıcı olarak kullanmamak için kodu biraz değiştirdim.
Serin geçici çözüm için tekrar teşekkürler 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
Oracle'da LISTAGG toplama işlevini kullanabilirsiniz.
Orijinal kayıtlar
name type
------------
name1 type1
name2 type2
name2 type3
sQL
SELECT name, LISTAGG(type, '; ') WITHIN GROUP(ORDER BY name)
FROM table
GROUP BY name
Sonuçlanmak
name type
------------
name1 type1
name2 type2; type3
Bu tür bir soru burada çok sık soruluyor ve çözüm, temel gereksinimlere çok bağlı olacak:
https://stackoverflow.com/search?q=sql+pivot
ve
https://stackoverflow.com/search?q=sql+concatenate
Genellikle, bunu dinamik sql, kullanıcı tanımlı bir işlev veya imleç olmadan yapmanın yalnızca SQL yolu yoktur.
Sadece Cade'nin söylediklerine eklemek için, bu genellikle bir ön uç görüntüleme şeyidir ve bu nedenle orada ele alınmalıdır. Bazen dosya dışa aktarma veya diğer "yalnızca SQL" çözümleri gibi şeyler için SQL'de% 100 bir şey yazmak daha kolaydır, ancak çoğu zaman bu birleştirme ekran katmanınızda ele alınmalıdır.
İmlece gerek yok ... while döngüsü yeterlidir.
------------------------------
-- 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
Çok basit olalım:
SELECT stuff(
(
select ', ' + x from (SELECT 'xxx' x union select 'yyyy') tb
FOR XML PATH('')
)
, 1, 2, '')
Bu satırı değiştirin:
select ', ' + x from (SELECT 'xxx' x union select 'yyyy') tb
Sorgunuzla.
herhangi bir çapraz uygulama cevapları görmedim, ayrıca xml ekstraksiyonuna gerek yok. İşte Kevin Fairchild'in yazdıklarının biraz farklı bir versiyonu. Daha karmaşık sorgularda kullanımı daha hızlı ve kolaydır:
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
Gruplandırma çoğunlukla tek bir öğe içeriyorsa performansı önemli ölçüde aşağıdaki şekilde artırabilirsiniz:
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
Replace Function ve FOR JSON PATH kullanma
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
Örnek veriler ve daha fazla yol için buraya tıklayın
Clr'yi etkinleştirdiyseniz GitHub'daki Group_Concat kütüphanesini kullanabilirsiniz
GROUP_CONCAT()
toplama işlevi ile MySQL'de kolayca çözülür , ancak Microsoft SQL Server'da çözmek daha gariptir. Yardım için aşağıdaki SO sorusuna bakın: " İlişkiye dayalı bir kayıtta birden çok kayıt nasıl elde edilir? "