T-SQL ha una funzione aggregata per concatenare le stringhe?

Possibili duplicati:
Funzione di tipo Implode in SQL Server 2000?
Valori di riga concatenati T-SQL

Ho una vista che sto interrogando che assomiglia a questo:

BuildingName PollNumber ------------ ---------- Foo Centre 12 Foo Centre 13 Foo Centre 14 Bar Hall 15 Bar Hall 16 Baz School 17 

Devo scrivere una query che raggruppa BuildingNames e visualizza un elenco di PollNumbers come questo:

 BuildingName PollNumbers ------------ ----------- Foo Centre 12, 13, 14 Bar Hall 15, 16 Baz School 17 

Come posso farlo in T-SQL? Preferirei non ricorrere a scrivere una stored procedure per questo, dal momento che sembra eccessivo, ma non sono esattamente una persona di database. Sembra che una funzione aggregata come SUM () o AVG () sia ciò di cui ho bisogno, ma non so se T-SQL ne abbia uno. Sto usando SQL Server 2005.

per SQL Server 2017 e versioni successive:

STRING_AGG ()

 set nocount on; declare @YourTable table (RowID int, HeaderValue int, ChildValue varchar(5)) insert into @YourTable VALUES (1,1,'CCC') insert into @YourTable VALUES (2,2,'B< &>B') insert into @YourTable VALUES (3,2,'AAA') insert into @YourTable VALUES (4,3,'
') insert into @YourTable VALUES (5,3,'A & Z') set nocount off SELECT t1.HeaderValue ,STUFF( (SELECT ', ' + t2.ChildValue FROM @YourTable t2 WHERE t1.HeaderValue=t2.HeaderValue ORDER BY t2.ChildValue FOR XML PATH(''), TYPE ).value('.','varchar(max)') ,1,2, '' ) AS ChildValues FROM @YourTable t1 GROUP BY t1.HeaderValue SELECT HeaderValue, STRING_AGG(ChildValue,', ') FROM @YourTable GROUP BY HeaderValue

PRODUZIONE:

 HeaderValue ----------- ------------- 1 CCC 2 B< &>B, AAA 3 
, A & Z (3 rows affected)

per SQL Server 2005 e fino al 2016, devi fare qualcosa di simile a questo:

 --Concatenation with FOR XML and eleminating control/encoded character expansion "& <>" set nocount on; declare @YourTable table (RowID int, HeaderValue int, ChildValue varchar(5)) insert into @YourTable VALUES (1,1,'CCC') insert into @YourTable VALUES (2,2,'B< &>B') insert into @YourTable VALUES (3,2,'AAA') insert into @YourTable VALUES (4,3,'
') insert into @YourTable VALUES (5,3,'A & Z') set nocount off SELECT t1.HeaderValue ,STUFF( (SELECT ', ' + t2.ChildValue FROM @YourTable t2 WHERE t1.HeaderValue=t2.HeaderValue ORDER BY t2.ChildValue FOR XML PATH(''), TYPE ).value('.','varchar(max)') ,1,2, '' ) AS ChildValues FROM @YourTable t1 GROUP BY t1.HeaderValue

PRODUZIONE:

 HeaderValue ChildValues ----------- ------------------- 1 CCC 2 AAA, B< &>B 3 
, A & Z (3 row(s) affected)

Inoltre, attenzione, non tutte le concatenazioni FOR XML PATH gestiranno correttamente i caratteri speciali XML come sarà il mio esempio precedente.

Non esiste una funzione incorporata in Sql Server, ma può essere ottenuta scrivendo un aggregato definito dall’utente. Questo articolo menziona tale funzione come parte degli esempi di SQL Server: http://msdn.microsoft.com/en-us/library/ms182741.aspx

Ad esempio, includo il codice per un aggregato concatenato. Per utilizzarlo, creare un progetto di database in Visual Studio, aggiungere nuovo SqlAggregate e sostituire il codice con l’esempio seguente. Una volta implementato, dovresti trovare un nuovo assembly nel tuo database e una funzione aggregata Concatenate

 using System; using System.Data.SqlTypes; using System.IO; using System.Text; using Microsoft.SqlServer.Server; [Serializable] [SqlUserDefinedAggregate(Format.UserDefined, IsInvariantToNulls = true, IsInvariantToDuplicates = false, IsInvariantToOrder = false, MaxByteSize = 8000, Name = "Concatenate")] public class Concatenate : IBinarySerialize { private StringBuilder _intermediateResult; internal string IntermediateResult { get { return _intermediateResult.ToString(); } } public void Init() { _intermediateResult = new StringBuilder(); } public void Accumulate(SqlString value) { if (value.IsNull) return; _intermediateResult.Append(value.Value); } public void Merge(Concatenate other) { if (null == other) return; _intermediateResult.Append(other._intermediateResult); } public SqlString Terminate() { var output = string.Empty; if (_intermediateResult != null && _intermediateResult.Length > 0) output = _intermediateResult.ToString(0, _intermediateResult.Length - 1); return new SqlString(output); } public void Read(BinaryReader reader) { if (reader == null) throw new ArgumentNullException("reader"); _intermediateResult = new StringBuilder(reader.ReadString()); } public void Write(BinaryWriter writer) { if (writer == null) throw new ArgumentNullException("writer"); writer.Write(_intermediateResult.ToString()); } } 

Per usarlo, puoi semplicemente scrivere una query aggregata:

 create table test( id int identity(1,1) not null primary key , class tinyint not null , name nvarchar(120) not null ) insert into test values (1, N'This'), (1, N'is'), (1, N'just'), (1, N'a'), (1, N'test'), (2, N','), (3, N'do'), (3, N'not'), (3, N'be'), (3, N'alarmed'), (3, N','), (3, N'this'), (3, N'is'), (3, N'just'), (3, N'a'), (3, N'test') select dbo.Concatenate(name + ' ') from test group by class drop table test 

L’output della query è:

 -- Output -- =================== -- This is just a test -- , -- do not be alarmed , this is just a test 

Ho impacchettato la class e l’aggregato come uno script che puoi trovare qui: https://gist.github.com/FilipDeVos/5b7b4addea1812067b09