Reputation: 3707
I have a query that looks like this
SELECT J.JobID,T.Title FROM JobsTagMap J
Left Join Tags T
ON J.TagID=T.TagID
That returns the following dataset (simplified, JobID is actually a UniqueIdentifier)
JobID Title
1 Tag1
1 Tag2
2 Tag2
2 Tag5
2 Tag9
Now, i'd like to group this by the JobID-column and concatenate the Title, so the results is as following
JobID Title
1 Tag1,Tag2
2 Tag2,Tag5,Tag9
How would i do that?
Upvotes: 4
Views: 20152
Reputation: 115
I had the same problem as you did and I figured out how to workaround slow sub-selects.
Using GROUP BY:
(70500 rows affected)
SQL Server Execution Times:
CPU time = 94 ms, elapsed time = 833 ms.
Using Sub-Selects:
(70500 rows affected)
SQL Server Execution Times:
CPU time = 1469 ms, elapsed time = 2323 ms.
Sub-selects are more then 4 times slower...
Here's the solution:
SELECT
J.JobID,
STRING_AGG(ISNULL(T.Title, ''), ',') as Title
FROM JobsTagMap J
LEFT JOIN Tags T ON J.TagID = T.TagID
GROUP BY J.JobID;
Let me know if something is not clear enough :)
Upvotes: -1
Reputation: 31249
If you are using sql server 2005+. Then you can do like this:
SELECT
JobsTagMap.JobID,
STUFF
(
(
SELECT
',' +Title
FROM
Tags
WHERE
Tags.TagID=JobsTagMap.TagID
FOR XML PATH('')
)
,1,1,'') AS Title
FROM JobsTagMap
EDIT
Because you did not show us the table structure and the data in the different tables. It was a lite bit hard to know. So I assume that your table structure looks something like this:
CREATE TABLE JobsTagMap
(
JobID INT,
TagID INT
)
CREATE TABLE Tags
(
TagID INT,
Title VARCHAR(100)
)
With this data:
INSERT INTO JobsTagMap
VALUES(1,1),(1,2),(2,2),(2,4),(2,5)
INSERT INTO Tags
VALUES(1,'Tag1'),(2,'Tag2'),(3,'Tag2'),(4,'Tag5'),(5,'Tag9')
If you are getting that data that you are showing the JobID
cannot be unique. You might have the a Job
table somewhere where it is unique. If you just want to use these table that you are showing then you need to do something like this:
;WITH CTE
AS
(
SELECT
ROW_NUMBER() OVER(PARTITION BY JobID ORDER BY JobID) AS RowNbr,
JobsTagMap.*
FROM
JobsTagMap
)
SELECT
*,
STUFF
(
(
SELECT
',' +Title
FROM
Tags
JOIN JobsTagMap
ON Tags.TagID=JobsTagMap.TagID
WHERE
JobsTagMap.JobID=CTE.JobID
FOR XML PATH('')
)
,1,1,'') AS Title
FROM
CTE
WHERE
CTE.RowNbr=1
This will get you this result:
1 1 1 Tag1,Tag2
1 2 2 Tag2,Tag5,Tag9
So in the future always show what table structure and it data. That will give you better answers
Upvotes: 10
Reputation: 45096
I use a scalar function for exactly that. There are going to be some purist that decry should never use a row based operation but hey this works and if you are only returning a few rows then response time is fine.
CREATE FUNCTION [dbo].[JoinMVText]
(
@sID int,
@fieldID tinyint
)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE @MVtextList varchar(max)
SELECT @MVtextList = COALESCE(@MVtextList + '; ', '') + docMVtext.value
FROM docMVtext with (nolock)
WHERE docMVtext.sID = @sID and fieldID = @fieldID
RETURN @MVtextList
END
Upvotes: 1