Silly it may be but sometimes de-normalized relationships make more sense to the end-user. The following function presents a way to list related records (in the Northwind database) in a flat table, where in this case the names of products in an order can be listed in a single column as comma-delimited values. Also known as: aggregate concatenation.
create function dbo.fnGet_ProductName_asArray
(
@OrderID int
,@Separator nvarchar(16) = null
)
returns nvarchar(4000)
as
begin
declare @productNameArray nvarchar(4000)
if (@Separator is null)
begin
set @Separator = N', '
end
set @productNameArray = N''
select @productNameArray
= @productNameArray
+ @Separator
+ convert(nvarchar(4000), isnull(dbo.Products.ProductName, N''))
from dbo.[Order Details]
inner join dbo.Products
on dbo.Products.ProductID = dbo.[Order Details].ProductID
where (dbo.[Order Details].OrderID = @OrderID)
order by dbo.Products.ProductName
set @productNameArray = ltrim(rtrim(substring(@productNameArray,
len(@Separator) + 1, len(@productNameArray))))
return @productNameArray
end
go
Please, use this function for presentation purposes only. Better still - use appropriate presentation components to do this on the client-side.
WARNING!
There are known issues with aggregate concatenation in T-SQL:
- PRB: Execution Plan and Results of Aggregate Concatenation Queries Depend Upon Expression Location;
- Bug Details: Expression in ORDER BY clause causes self-referencing variables in the SELECT clause to evaluate only once rather than once per row.
Still, here's an example of use:
select dbo.[Order Details].OrderID
,dbo.fnGet_ProductName_asArray
(dbo.[Order Details].OrderID, N' | ') as ProductNames
from dbo.[Order Details]
inner join dbo.Products
on dbo.Products.ProductID = dbo.[Order Details].ProductID
group by dbo.[Order Details].OrderID
ML
p.s. In SQL Server 2005 there are alternatives...
No comments:
Post a Comment