Ortamınızda CLR kullanma izniniz varsa, bu, kullanıcı tanımlı bir toplama için özel olarak hazırlanmış bir durumdur.
Özellikle, kaynak veriler önemsiz derecede büyükse ve / veya bu tür bir şeyi uygulamanızda çok fazla yapmanız gerekiyorsa, muhtemelen bu yoldur. Aaron'un çözümü için sorgu planının girdi boyutu büyüdükçe iyi ölçeklenmeyeceğinden şüpheleniyorum . (Geçici tabloya bir dizin eklemeyi denedim, ancak bu yardımcı olmadı.)
Bu çözüm, diğer birçok şey gibi, bir ödünleşmedir:
- CLR Entegrasyonunu sizin veya müşterinizin ortamında bile kullanmak için politika / politika.
- CLR işlevi daha hızlıdır ve gerçek bir veri kümesi göz önüne alındığında daha iyi ölçeklendirilir.
- CLR işlevi diğer sorgularda yeniden kullanılabilir ve bu tür şeyleri her yapmanız gerektiğinde karmaşık bir alt sorguyu çoğaltmanız (ve hata ayıklamanız) gerekmez.
- Düz T-SQL bir parça harici kod yazmaktan ve yönetmekten daha kolaydır.
- Belki de C # veya VB'de nasıl programlayacağınızı bilmiyorsunuz.
- vb.
DÜZENLEME: Eh, bunun gerçekten daha iyi olup olmadığını görmek için gittim ve yorumların belirli bir sırayla olması şartıyla bir toplama işlevi kullanarak tatmin etmek mümkün değildir. :(
Bkz. SqlUserDefinedAggregateAttribute.IsInvariantToOrder . Temelde, ne yapmak gerekir olduğunu OVER(PARTITION BY customer_code ORDER BY row_num)
ancak ORDER BY
desteklenmez OVER
toplama yaparken maddesi. Bu işlevselliği SQL Server'a ekleyerek yürütme planında değiştirilmesi gerekecek çünkü solucanlar bir kutu açar varsayıyorum. Yukarıda adı geçen bağlantı, bunun gelecekteki kullanım için ayrıldığını söylüyor, bu nedenle bu gelecekte uygulanabilir (2005'te muhtemelen şansınız kalmadı).
Bu olabilir hala paketleme ve ayrıştırma ile gerçekleştirilebilir row_num
oldukça hackish görünüyor CLR nesne içinde çeşit ... yapıyor sonra toplanan dizeye değer ve.
Her halükarda, başka birinin bu sınırlamada bile yararlı bulması durumunda kullandığım kod aşağıdadır. Bilgisayar korsanlığını okuyucu için bir egzersiz olarak bırakacağım. Test verileri için AdventureWorks (2005) kullandığımı unutmayın.
Agrega montajı:
using System;
using System.IO;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
namespace MyCompany.SqlServer
{
[Serializable]
[SqlUserDefinedAggregate
(
Format.UserDefined,
IsNullIfEmpty = false,
IsInvariantToDuplicates = false,
IsInvariantToNulls = true,
IsInvariantToOrder = false,
MaxByteSize = -1
)]
public class StringConcatAggregate : IBinarySerialize
{
private string _accum;
private bool _isEmpty;
public void Init()
{
_accum = string.Empty;
_isEmpty = true;
}
public void Accumulate(SqlString value)
{
if (!value.IsNull)
{
if (!_isEmpty)
_accum += ' ';
else
_isEmpty = false;
_accum += value.Value;
}
}
public void Merge(StringConcatAggregate value)
{
Accumulate(value.Terminate());
}
public SqlString Terminate()
{
return new SqlString(_accum);
}
public void Read(BinaryReader r)
{
this.Init();
_accum = r.ReadString();
_isEmpty = _accum.Length == 0;
}
public void Write(BinaryWriter w)
{
w.Write(_accum);
}
}
}
Test için T-SQL ( CREATE ASSEMBLY
ve sp_configure
CLR'yi atlamak için):
CREATE TABLE [dbo].[Comments]
(
CustomerCode int NOT NULL,
RowNum int NOT NULL,
Comments nvarchar(25) NOT NULL
)
INSERT INTO [dbo].[Comments](CustomerCode, RowNum, Comments)
SELECT
DENSE_RANK() OVER(ORDER BY FirstName),
ROW_NUMBER() OVER(PARTITION BY FirstName ORDER BY ContactID),
Phone
FROM [AdventureWorks].[Person].[Contact]
GO
CREATE AGGREGATE [dbo].[StringConcatAggregate]
(
@input nvarchar(MAX)
)
RETURNS nvarchar(MAX)
EXTERNAL NAME StringConcatAggregate.[MyCompany.SqlServer.StringConcatAggregate]
GO
SELECT
CustomerCode,
[dbo].[StringConcatAggregate](Comments) AS AllComments
FROM [dbo].[Comments]
GROUP BY CustomerCode