У T-SQL есть сводная функция для объединения строк?
Возможные дубликаты:
Функция типа Implode в SQL Server 2000?
Объединить значения строк 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.
Ответы
Ответ 1
нет, для 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
ВЫВОД:
HeaderValue ChildValues
----------- -------------------
1 CCC
2 AAA, B<&>B
3 <br>, A & Z
(3 row(s) affected)
Кроме того, обратите внимание, что не все FOR XML PATH
конкатенации будут корректно обрабатывать специальные символы XML, как мой пример выше.
Ответ 2
В 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());
}
}
Чтобы использовать его, вы можете просто написать сводный запрос:
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
Я упаковал класс и агрегат как script, который вы можете найти здесь: https://gist.github.com/FilipDeVos/5b7b4addea1812067b09