I've written this query with the help of google to create a delimited list from a table but I didn't understand anything from this query.
Can anyone explain me what's happening
SELECT
E1.deptno,
allemp = Replace ((SELECT E2.ename AS 'data()'
FROM emp AS e2
WHERE e1.deptno = e2.DEPTNO
FOR xml PATH('')), ' ', ', ')
FROM EMP AS e1
GROUP BY DEPTNO;
Gives me result
10 CLARK, KING, MILLER
20 SMITH, JONES, SCOTT, ADAMS, FORD
30 ALLEN, WARD, MARTIN, BLAKE, TURNER, JAMES
The simplest way of explaining it is to look at how
FOR XML PATH
works for actual XML. Imagine a simple tableEmployee
:You could use
This would create XML as follows
Removing the 'Employee' from
PATH
removes the outer xml tags so this query:Would create
What you are then doing is not ideal, the column name 'data()' forces an sql error because it is trying to create an xml tag which is not a legal tag, so the following error is generated:
The correlated subquery hides this error and just generates the XML with no tags:
creates
You are then replacing spaces with commas, fairly self explanatory...
If I were you I would adapt the query slightly:
Having no column alias will mean no xml tags are created, and adding the comma within the select query means any names with spaces in will not cause errors,
STUFF
will remove the first comma and space.ADDENDUM
To elaborate on what KM has said in a comment, as this seems to be getting a few more views, the correct way to escape XML characters would be to use
.value
as follows:SQL Server 2017 makes this much easier with the new
STRING_AGG
. Recently came across this post and switched my STUFF/FOR XML strategy to use the new string function. Also avoids the need to do an extra JOIN/SUBQUERYand the overhead of FOR XML (and the odd-encoding issues) and hard to interpret SQL.Note: Also be sure to check out the counterpart
STRING_SPLIT
to make working with SQL delimited data much easier.The outer query retrieves a list of department numbers, and the subquery is then run for each department number to return all names belonging to that department. The subquery uses the FOR XML statement to format the output into a single line comma separated list.
Take it apart step by step - from the inside out.
Step 1:
Run the innermost query and see what it produces:
You should get an output something like:
Step 2:
The
REPLACE
just replaces spaces with,
- thus turning your output intoStep 3:
The outer query gets the
deptno
value - plus the results from the inner query - and produces your final result.