BLOGS BY TOPIC▼
BLOGS BY AUTHOR▼
BLOGS BY YEAR▼
If you want to group items in a SQL query, showing a comma-delimited list of ids for each, generating an XML file is not the obvious place to start - but it should be.
- Using FOR XML in SQL to group and concatenate ids
- Generating XML from SQL using FOR XML PATH
- Combining grouping, STUFF and FOR XML in a single query (this blog)
Posted by Andy Brown on 27 September 2016
You need a minimum screen resolution of about 700 pixels width to see our blogs. This is because they contain diagrams and tables which would not be viewable easily on a mobile phone or small laptop. Please use a larger tablet, notebook or desktop computer, or change your screen resolution settings.
Combining grouping, STUFF and FOR XML in a single query
I'm gradually sneaking up on the final answer to the challenge I set at the start of this blog.
As I mentioned at the start of this blog, if you want to learn more about SQL, why not treat yourself to a place on one of our introductory or advanced SQL online or classroom courses?
The basic GROUP BY query shell
What we want to do is to replace the selected text in this query:

Instead of displaying Answer here, we want to show the list of course ids, comma-separated.
This will allow us to show the course ids in the second column of the query output:

Here's what we get for now.
Final digression - the STUFF function in SQL
One last bit of SQL we'll need is the STUFF function, which takes four arguments:
Argument | What it contains | Example |
---|---|---|
1 | String to search | 'Wise Owl Training' |
2 | Where to start | 6 |
3 | How many characters to replace | 3 |
4 | Text to put instead | 'Frog' |
The example above could be shown using this statement:
-- rename Wise Owl
SELECT STUFF('Wise Owl Training', 6, 3, 'Frog')
This would produce this when run:

A better name? Perhaps not.
For our example, we can use the STUFF function to get rid of the opening comma at the start of each list.
The final SQL query
So here's the final query:
-- show course ids for each person
SELECT
p.PersonName,
STUFF((
SELECT ',' + CAST(innerTable.CourseId AS varchar(10))
FROM tblPerson AS innerTable
WHERE innerTable.PersonName = p.PersonName
FOR XML PATH('')
),1,1,'') AS Ids
FROM
tblPerson AS p
GROUP BY
p.PersonName
This produces the following results:

The output from running the above query.
This uses a correlated subquery to list out two columns for each person:
- The name of the person.
- The XML text listing the course ids for this person, with all node names and the leading comma removed.
Hopefully this now makes sense!
- Using FOR XML in SQL to group and concatenate ids
- Generating XML from SQL using FOR XML PATH
- Combining grouping, STUFF and FOR XML in a single query (this blog)