in
Eric Vaillancourt on SQL Server...

MS SQL Dev

How to combine multiple rows of data on same line.

Bookmark and Share

I’m often ask how combine information on same line in a query.  Let me explain, lets say that you would like to list all products from the Production.product table in the AdventureWorks database and that you would like to list ALL vendors for each product from the Purchasing.Vendor table on the same line. 

Look at the following example:

 

clip_image002

 

You can see in the 3rd column that all venders are list separated by a comma.

 

In the AdventureWorks database the relation between the Product table and the Vendor table in done through a third table called ProductVendor.  Look at the following diagram:

clip_image004

 

Let’s start with this simple query that uses inner joins to link all three tables:

 

SELECT Production.Product.Name AS [Product Name],

       Production.Product.ProductNumber,

       Purchasing.Vendor.Name AS Vendor

FROM Production.Product INNER JOIN Purchasing.ProductVendor

     ON Production.Product.ProductID = Purchasing.ProductVendor.ProductID

INNER JOIN Purchasing.Vendor

     ON Purchasing.ProductVendor.VendorID = Purchasing.Vendor.VendorID

ORDER BY [Product Name]

 

When you execute this query, you get the following:

 

clip_image006

 

In this example, we get all vendors on separate rows.  Not exactly what we want.  To solve this issue, we need to create a user defined function that will return all of our rows on a single line.  

Execute the script below:

 

 

CREATE FUNCTION [dbo].[ufnVendorOnSameLine](@Id int,@Delimiter varchar(10))

RETURNS nvarchar(max)

AS

BEGIN

DECLARE @OnSameLine varchar(max)

set @OnSameLine=''

--

--by using SELECT to set the variable, all rows are concatenated together.

SELECT @OnSameLine = @OnSameLine + coalesce (Purchasing.Vendor.Name,'')+@Delimiter

FROM  Purchasing.ProductVendor INNER JOIN Purchasing.Vendor

      ON Purchasing.ProductVendor.VendorID = Purchasing.Vendor.VendorID

WHERE (Purchasing.ProductVendor.ProductID = @Id)

--

--we need to remove the last delimiter

set @OnSameLine = substring(@OnSameLine,1,len(@OnSameLine)-1)

RETURN @OnSameLine

END;

 

Once we have created the udf, we need to modify the query to remove the Purchasing.Vendor.Name column and replace it with the function.  Also, we need to include a DISTINCT since we are unse an inner join to the Purchasing.ProductVendor table and finally, we remove the inner join to the Purchasing.Vendor table:

 

SELECT DISTINCT Production.Product.Name AS [Product Name],

                Production.Product.ProductNumber,

                dbo.ufnVendorOnSameLine(ProductVendor.ProductID,', ') AS Vendors

FROM Production.Product INNER JOIN Purchasing.ProductVendor

     ON Production.Product.ProductID = Purchasing.ProductVendor.ProductID

ORDER BY [Product Name]

 

How it Works:

 

Basicaly, we use a technique that has been around since the early day of MS SQL Sever.  In fact prior to version 7, the SET command did not exist.  We needed to use the SELECT to assign a value to a variable. For example:

 

SELECT @OnSameLine = @OnSameLine + coalesce (Purchasing.Vendor.Name,'')+@Delimiter

and

SET @OnSameLine = @OnSameLine + coalesce (Purchasing.Vendor.Name,'')+@Delimiter

Are the same…it’s just a long forgotten technique.

 

Hope this was useful,

 

Eric Vaillancourt

 

Comments

 

DotNetKicks.com said:

You've been kicked (a good thing) - Trackback from DotNetKicks.com

April 3, 2008 5:04 PM

About Eric Vaillancourt

Eric Vaillancourt possède plus de vingt ans d'expérience en programmation de base de données et en gestion de projets. Depuis une dizaine d’années, il se spécialise en optimisation des performances et en coaching d’administrateurs de bases de données. Il a occupé des postes de haute direction dans le secteur privé, principalement dans des firmes technologiques. Il a eu l'occasion de gérer plusieurs projets liés au développement des affaires et aux changements organisationnels.
©2008 SQLProf.com & Eric Vaillancourt
Powered by Community Server (Non-Commercial Edition), by Telligent Systems