patternsqlMinor
Multiple column concatenation
Viewed 0 times
concatenationmultiplecolumn
Problem
How to concatenate multiple columns in to a single row? For example:
The expected result set is:
Using a solution I found on Stack Overflow:
Are there any better solutions? The inner select comes from an expensive multi-table join (not the single table 'test' shown above). The query is in an in-line TVF, so I cannot use a temporary table.
Also, if there is a blank column the results will yield extra commas
like
Is there any way to prevent this?
id name car
1 sam dodge
1 ram maserati
1 john benz
1 NULL mazda
2 kirk lexus
2 Jim rolls
1 GMCThe expected result set is:
ID name car
1 sam,ram,john dodge,maserati,benz,mazda,GMC
2 kirk,jim lexus,rollsUsing a solution I found on Stack Overflow:
SELECT * FROM (
SELECT t.id,stuff([m].query('/name').value('/', 'varchar(max)'),1,1,'') AS [SomeField_Combined1],
stuff([m].query('/car').value('/', 'varchar(max)'),1,1,'') AS [SomeField_Combined2]
FROM dbo.test t
OUTER apply(SELECT (
SELECT id, ','+name AS name
,','+car AS car
FROM test WHERE test.id=t.id
FOR XML PATH('') ,type)
AS M) A)S
GROUP BY id,somefield_combined1,somefield_combined2Are there any better solutions? The inner select comes from an expensive multi-table join (not the single table 'test' shown above). The query is in an in-line TVF, so I cannot use a temporary table.
Also, if there is a blank column the results will yield extra commas
like
ID name car
1 sam,ram,john,, dodge,maserati,benz,mazda,GMC
2 kirk,jim lexus,rollsIs there any way to prevent this?
Solution
I ran a few tests using a little over 6 mil rows. With an index on the ID column.
Here is what I came up with.
Your initial query:
This one ran for ~23 minutes.
I ran this version which is the version I first learned. In some ways it seems like it should take longer but it doesn't.
This version ran in just over 2 minutes.
Here is what I came up with.
Your initial query:
SELECT * FROM (
SELECT t.id,
stuff([M].query('/name').value('/', 'varchar(max)'),1,1,'') AS [SomeField_Combined1],
stuff([M].query('/car').value('/', 'varchar(max)'),1,1,'') AS [SomeField_Combined2]
FROM dbo.test t
OUTER APPLY(SELECT (
SELECT id, ','+name AS name
,','+car AS car
FROM test WHERE test.id=t.id
FOR XML PATH('') ,type)
AS M)
M ) S
GROUP BY id, SomeField_Combined1, SomeField_Combined2This one ran for ~23 minutes.
I ran this version which is the version I first learned. In some ways it seems like it should take longer but it doesn't.
SELECT test.id,
STUFF((SELECT ', ' + ThisTable.name
FROM test ThisTable
WHERE test.id = ThisTable.id
AND ThisTable.name <> ''
FOR XML PATH ('')),1,2,'') AS ConcatenatedSomeField,
STUFF((SELECT ', ' + car
FROM test ThisTable
WHERE test.id = ThisTable.id
AND ThisTable.car <> ''
FOR XML PATH ('')),1,2,'') AS ConcatenatedSomeField2
FROM test
GROUP BY idThis version ran in just over 2 minutes.
Code Snippets
SELECT * FROM (
SELECT t.id,
stuff([M].query('/name').value('/', 'varchar(max)'),1,1,'') AS [SomeField_Combined1],
stuff([M].query('/car').value('/', 'varchar(max)'),1,1,'') AS [SomeField_Combined2]
FROM dbo.test t
OUTER APPLY(SELECT (
SELECT id, ','+name AS name
,','+car AS car
FROM test WHERE test.id=t.id
FOR XML PATH('') ,type)
AS M)
M ) S
GROUP BY id, SomeField_Combined1, SomeField_Combined2SELECT test.id,
STUFF((SELECT ', ' + ThisTable.name
FROM test ThisTable
WHERE test.id = ThisTable.id
AND ThisTable.name <> ''
FOR XML PATH ('')),1,2,'') AS ConcatenatedSomeField,
STUFF((SELECT ', ' + car
FROM test ThisTable
WHERE test.id = ThisTable.id
AND ThisTable.car <> ''
FOR XML PATH ('')),1,2,'') AS ConcatenatedSomeField2
FROM test
GROUP BY idContext
StackExchange Database Administrators Q#125771, answer score: 7
Revisions (0)
No revisions yet.