How to Concatenate Multiple Rows

How to concatenate text from multiple rows into a single text string in SQL Server

If you are on SQL Server 2017 or Azure, see Mathieu Renda answer.

I had a similar issue when I was trying to join two tables with one-to-many relationships. In SQL 2005 I found that XML PATH method can handle the concatenation of the rows very easily.

If there is a table called STUDENTS

SubjectID       StudentName
---------- -------------
1 Mary
1 John
1 Sam
2 Alaina
2 Edward

Result I expected was:

SubjectID       StudentName
---------- -------------
1 Mary, John, Sam
2 Alaina, Edward

I used the following T-SQL:

SELECT Main.SubjectID,
LEFT(Main.Students,Len(Main.Students)-1) As "Students"
FROM
(
SELECT DISTINCT ST2.SubjectID,
(
SELECT ST1.StudentName + ',' AS [text()]
FROM dbo.Students ST1
WHERE ST1.SubjectID = ST2.SubjectID
ORDER BY ST1.SubjectID
FOR XML PATH (''), TYPE
).value('text()[1]','nvarchar(max)') [Students]
FROM dbo.Students ST2
) [Main]

You can do the same thing in a more compact way if you can concat the commas at the beginning and use substring to skip the first one so you don't need to do a sub-query:

SELECT DISTINCT ST2.SubjectID, 
SUBSTRING(
(
SELECT ','+ST1.StudentName AS [text()]
FROM dbo.Students ST1
WHERE ST1.SubjectID = ST2.SubjectID
ORDER BY ST1.SubjectID
FOR XML PATH (''), TYPE
).value('text()[1]','nvarchar(max)'), 2, 1000) [Students]
FROM dbo.Students ST2

Can I concatenate multiple MySQL rows into one field?

You can use GROUP_CONCAT:

SELECT person_id,
GROUP_CONCAT(hobbies SEPARATOR ', ')
FROM peoples_hobbies
GROUP BY person_id;

As Ludwig stated in his comment, you can add the DISTINCT operator to avoid duplicates:

SELECT person_id,
GROUP_CONCAT(DISTINCT hobbies SEPARATOR ', ')
FROM peoples_hobbies
GROUP BY person_id;

As Jan stated in their comment, you can also sort the values before imploding it using ORDER BY:

SELECT person_id, 
GROUP_CONCAT(hobbies ORDER BY hobbies ASC SEPARATOR ', ')
FROM peoples_hobbies
GROUP BY person_id;

As Dag stated in his comment, there is a 1024 byte limit on the result. To solve this, run this query before your query:

SET group_concat_max_len = 2048;

Of course, you can change 2048 according to your needs. To calculate and assign the value:

SET group_concat_max_len = CAST(
(SELECT SUM(LENGTH(hobbies)) + COUNT(*) * LENGTH(', ')
FROM peoples_hobbies
GROUP BY person_id) AS UNSIGNED);

SQL Server Concatenate Multiple Rows By Group Using FOR XML PATH

You need a correlated subquery:

SELECT hs.department AS department,
STUFF( (SELECT ', ' + top_employee
FROM findhighest_secondstep hs2
WHERE hs2.department = hs.department
FOR XML PATH('')
), 1, 2, ''
) as top_employees
FROM findhighest_secondstep hs
GROUP BY hs.department

Conditionally concatenate string over multiple rows

tidyverse way would be to fill the action column with previous non-NA value then group_by Action and paste the description together.

library(tidyverse)

df %>%
fill(action) %>%
group_by(action) %>%
summarise(description = paste(description, collapse = " "))

# action description
# <dbl> <chr>
#1 1. a b c
#2 2. a b
#3 3. a b c d
#4 4. a b

how to concatenate multiple rows into one

First of all, your desired output appears to have the 'name' column from your second input table as a comma-separated list, but your code implies that you want the 'code' column concatenated instead. This solution concatenates the 'name' column.

Second, looking at your input tables, you can't directly use join ORDERS o on o.FUNDER_ID=f.FUNDER_ID because 'B0000000019' does not equal 'F19'. However, once you manipulate those columns so they could be joined, try this:

SELECT DISTINCT o.dept_id, o.client_id
,(STUFF((SELECT distinct CAST(', ' + name AS VARCHAR(MAX))
FROM FUNDERS f
JOIN ORDERS o2 ON o2.funder_id = f.funder_id
FOR XML PATH ('')), 1, 2, '')) AS funder_code
FROM ORDERS o

How to concatenate multiple rows to single row without messing up the data?

The sub-query should reference the main query Field and AccessoryId

SELECT
Radi.Field,
(SELECT
a.AccessoryId+','
FROM
FieldAcce fa
INNER JOIN Radi r ON fa.RadiSer = r.RadiSer
INNER JOIN Acce a ON fa.AcceSer = a.AcceSer
WHERE
r.Id LIKE UPPER (@RNO)
AND r.CourseID LIKE @CourseID
AND r.PhaseId LIKE @PhaseID
-- add the following 2 lines
AND r.Field = Radi.Field
AND a.AccessoryId = Acce.AccessoryId
ORDER BY
r.Field
FOR XML PATH('')) AS [Accessory]
FROM
FieldAcce
INNER JOIN Radi ON FieldAcce.RadiSer = Radi.RadiSer
INNER JOIN Acce ON FieldAcce.AcceSer = Acce.AcceSer
WHERE
Radi.Id LIKE UPPER (@RNO)
AND Radi.CourseID LIKE @CourseID
AND Radi.PhaseId LIKE @PhaseID
GROUP BY
Radi.Field,
Acce.AccessoryId
ORDER BY
Radi.Field


Related Topics



Leave a reply



Submit