T-SQL有一个聚合函数来连接string吗?
可能重复:
SQL Server 2000中的Implodetypes函数?
连接行值T-SQL
我有一个观点,我正在查询,看起来像这样:
BuildingName PollNumber ------------ ---------- Foo Centre 12 Foo Centre 13 Foo Centre 14 Bar Hall 15 Bar Hall 16 Baz School 17
我需要编写一个将BuildingNames分组在一起的查询,并显示如下的PollNumbers列表:
BuildingName PollNumbers ------------ ----------- Foo Centre 12, 13, 14 Bar Hall 15, 16 Baz School 17
我怎样才能在T-SQL中做到这一点? 我宁愿不为这个写一个存储过程,因为它看起来像是过度杀伤,但我不完全是一个数据库的人。 看起来像SUM()或AVG()这样的聚合函数就是我所需要的,但是我不知道T-SQL是否有。 我正在使用SQL Server 2005。
不,对于SQL Server 2005来说,你需要做这样的事情:
--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,'<br>') 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
OUTPUT:
HeaderValue ChildValues ----------- ------------------- 1 CCC 2 AAA, B<&>B 3 <br>, A & Z (3 row(s) affected)
另外,注意,并不是所有的FOR XML PATH
连接都能正确处理像我上面例子那样的XML特殊字符。
Sql Server中没有内置函数,但可以通过编写用户定义的聚合来实现。 本文提到这样一个函数作为SQL Server示例的一部分: http : //msdn.microsoft.com/en-us/library/ms182741.aspx
作为一个例子,我包含了一个Concatenate聚合的代码。 要使用它,请在Visual Studio中创build一个数据库项目,添加新的SqlAggregate并将代码replace为下面的示例。 一旦部署,你应该在你的数据库中find一个新的程序集和一个聚合函数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()); } }
要使用它,你可以简单地写一个聚合查询:
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
查询的输出是:
-- Output -- =================== -- This is just a test -- , -- do not be alarmed , this is just a test
我打包了类和聚合作为脚本,你可以在这里find: https : //gist.github.com/FilipDeVos/5b7b4addea1812067b09