Bra*_*bby 76 t-sql sql-server group-by sql-server-2005 aggregate-functions
我有一个我正在查询的视图,看起来像这样:
Run Code Online (Sandbox Code Playgroud)BuildingName PollNumber ------------ ---------- Foo Centre 12 Foo Centre 13 Foo Centre 14 Bar Hall 15 Bar Hall 16 Baz School 17
我需要编写一个将BuildingNames组合在一起的查询,并显示一个PollNumbers列表,如下所示:
Run Code Online (Sandbox Code Playgroud)BuildingName PollNumbers ------------ ----------- Foo Centre 12, 13, 14 Bar Hall 15, 16 Baz School 17
我怎么能在T-SQL中做到这一点?我宁愿不为此写一个存储过程,因为它看起来有点矫枉过正,但我不是一个数据库人.看起来像SUM()或AVG()这样的聚合函数是我需要的,但我不知道T-SQL是否有一个.我正在使用SQL Server 2005.
KM.*_*KM. 114
对于SQL Server 2017及以上使用:
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,'<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
SELECT
HeaderValue, STRING_AGG(ChildValue,', ')
FROM @YourTable
GROUP BY HeaderValue
Run Code Online (Sandbox Code Playgroud)
OUTPUT:
HeaderValue
----------- -------------
1 CCC
2 B<&>B, AAA
3 <br>, A & Z
(3 rows affected)
Run Code Online (Sandbox Code Playgroud)
对于SQL Server 2005和2016年,您需要执行以下操作:
--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
Run Code Online (Sandbox Code Playgroud)
OUTPUT:
HeaderValue ChildValues
----------- -------------------
1 CCC
2 AAA, B<&>B
3 <br>, A & Z
(3 row(s) affected)
Run Code Online (Sandbox Code Playgroud)
另外,请注意,并非所有FOR XML PATH
连接都能正确处理上面示例中的XML特殊字符.
Fil*_*Vos 36
Sql Server中没有内置函数,但可以通过编写用户定义的聚合来实现.本文提到了这样一个函数作为SQL Server示例的一部分:http://msdn.microsoft.com/en-us/library/ms182741.aspx
作为示例,我包含了Concatenate聚合的代码.要使用它,请在Visual Studio中创建一个数据库项目,添加新的SqlAggregate并将代码替换为下面的示例.部署后,您应该在数据库中找到一个新程序集和一个聚合函数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());
}
}
Run Code Online (Sandbox Code Playgroud)
要使用它,您只需编写聚合查询:
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
Run Code Online (Sandbox Code Playgroud)
查询的输出是:
-- Output
-- ===================
-- This is just a test
-- ,
-- do not be alarmed , this is just a test
Run Code Online (Sandbox Code Playgroud)
我把这个类和聚合打包成一个脚本,你可以在这里找到:https://gist.github.com/FilipDeVos/5b7b4addea1812067b09
归档时间: |
|
查看次数: |
84998 次 |
最近记录: |