Table is:
+----+------+
| Id | Name |
+----+------+
| 1 | aaa |
| 1 | bbb |
| 1 | ccc |
| 1 | ddd |
| 1 | eee |
+----+------+
Required output:
+----+---------------------+
| Id | abc |
+----+---------------------+
| 1 | aaa,bbb,ccc,ddd,eee |
+----+---------------------+
Query:
SELECT ID,
abc = STUFF(
(SELECT ',' + name FROM temp1 FOR XML PATH ('')), 1, 1, ''
)
FROM temp1 GROUP BY id
This query is working properly. But I just need the explanation how it works or is there any other or short way to do this.
I am getting very confused to understand this.
I did debugging and finally returned my 'stuffed' query to it it's normal way.
Simply
gives me contents of the table to write to a log table from a trigger I debug.
This article covers various ways of concatenating strings in SQL, including an improved version of your code which doesn't XML-encode the concatenated values.
To understand what's happening, start with the inner query:
Because you're specifying
FOR XML
, you'll get a single row containing an XML fragment representing all of the rows.Because you haven't specified a column alias for the first column, each row would be wrapped in an XML element with the name specified in brackets after the
FOR XML PATH
. For example, if you hadFOR XML PATH ('X')
, you'd get an XML document that looked like:But, since you haven't specified an element name, you just get a list of values:
The
.value('.', 'varchar(max)')
simply retrieves the value from the resulting XML fragment, without XML-encoding any "special" characters. You now have a string that looks like:The
STUFF
function then removes the leading comma, giving you a final result that looks like:It looks quite confusing at first glance, but it does tend to perform quite well compared to some of the other options.
There is very new functionality in Azure SQL Database and SQL Server (starting with 2017) to handle this exact scenario. I believe this would serve as a native official method for what you are trying to accomplish with the XML/STUFF method. Example:
STRING_AGG - https://msdn.microsoft.com/en-us/library/mt790580.aspx
EDIT: When I originally posted this I made mention of SQL Server 2016 as I thought I saw that on a potential feature that was to be included. Either I remembered that incorrectly or something changed, thanks for the suggested edit fixing the version. Also, pretty impressed and wasn't fully aware of the multi-step review process that just pulled me in for a final option.
Here in the above query STUFF function is used to just remove the first comma
(,)
from the generated xml string(,aaa,bbb,ccc,ffffd,eee)
then it will become(aaa,bbb,ccc,ffffd,eee)
.And
FOR XML PATH('')
simply converts column data into(,aaa,bbb,ccc,ffffd,eee)
string but in PATH we are passing '' so it will not create a XML tag.And at the end we have grouped records using ID column.
Im frequently using with where clause
Here is how it works:
1. Get XML element string with FOR XML
Adding FOR XML PATH to the end of a query allows you to output the results of the query as XML elements, with the element name contained in the PATH argument. For example, if we were to run the following statement:
By passing in a blank string (FOR XML PATH('')), we get the following instead:
2. Remove leading comma with STUFF
The STUFF statement literally "stuffs” one string into another, replacing characters within the first string. We, however, are using it simply to remove the first character of the resultant list of values.
The parameters of
STUFF
are:So we end up with:
3. Join on id to get full list
Next we just join this on the list of id in the temp table, to get a list of IDs with name:
And we have our result:
Hope this helps!