Nếu bạn được phép sử dụng CLR trong môi trường của mình, đây là trường hợp được thiết kế riêng cho tổng hợp do người dùng xác định.
Đặc biệt, đây có lẽ là cách để đi nếu dữ liệu nguồn không quá lớn và / hoặc bạn cần thực hiện loại điều này rất nhiều trong ứng dụng của mình. Tôi hoàn toàn nghi ngờ kế hoạch truy vấn cho giải pháp của Aaron sẽ không mở rộng được khi kích thước đầu vào tăng lên. (Tôi đã thử thêm một chỉ mục vào bảng tạm thời, nhưng điều đó không có ích.)
Giải pháp này, giống như nhiều thứ khác, là một sự đánh đổi:
- Chính trị / chính sách thậm chí sử dụng Tích hợp CLR trong môi trường của bạn hoặc của khách hàng của bạn.
- Chức năng CLR có khả năng nhanh hơn và sẽ mở rộng tốt hơn khi có một bộ dữ liệu thực sự.
- Hàm CLR sẽ có thể được sử dụng lại trong các truy vấn khác và bạn sẽ không phải sao chép (và gỡ lỗi) một truy vấn con phức tạp mỗi khi bạn cần thực hiện loại điều này.
- Straight T-SQL đơn giản hơn viết và quản lý một đoạn mã bên ngoài.
- Có lẽ bạn không biết cách lập trình trong C # hoặc VB.
- Vân vân.
EDIT: Chà, tôi đã cố gắng xem liệu điều này có thực sự tốt hơn không, và hóa ra yêu cầu rằng các bình luận theo một thứ tự cụ thể hiện không thể đáp ứng bằng cách sử dụng hàm tổng hợp. :(
Xem SqlUserDefinedAggregateAttribution.IsInvariantToOrder . Về cơ bản, những gì bạn cần làm là OVER(PARTITION BY customer_code ORDER BY row_num)
nhưng ORDER BY
không được hỗ trợ trong OVER
mệnh đề khi tổng hợp. Tôi giả sử việc thêm chức năng này vào SQL Server sẽ mở ra một hộp giun, bởi vì những gì cần phải thay đổi trong kế hoạch thực hiện là không đáng kể. Liên kết nói trên cho biết điều này được dành riêng cho sử dụng trong tương lai, vì vậy điều này có thể được thực hiện trong tương lai (mặc dù vào năm 2005, bạn có thể không gặp may).
Điều này vẫn có thể được thực hiện bằng cách đóng gói và phân tích cú pháprow_num
giá trị vào chuỗi tổng hợp, và sau đó thực hiện sắp xếp trong đối tượng CLR ... có vẻ khá hackish.
Trong mọi trường hợp, dưới đây là mã tôi đã sử dụng trong trường hợp bất kỳ ai khác thấy điều này hữu ích ngay cả với giới hạn. Tôi sẽ để lại phần hack như một bài tập cho người đọc. Lưu ý rằng tôi đã sử dụng AdventureWorks (2005) cho dữ liệu thử nghiệm.
Lắp ráp tổng hợp:
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);
}
}
}
T-SQL để kiểm tra ( CREATE ASSEMBLY
và sp_configure
để bật CLR bị bỏ qua):
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