FOR XML EXPLICIT can be a little awkward to use to say the least, but it has it uses. The good thing about EXPLICIT, is that you can mold it into almost any structure you like.
I actually found that reviewing the results as tabular data is what really helped me understand what the FOR XML EXPLICIT query is doing.
Below is the example code that I’m using:
SELECT
1 AS Tag,
NULL AS Parent,
Name AS "Person!1!Name",
PersonId AS "Person!1!PersonId",
NULL AS "Orders!2!Item"
FROM Person
UNION ALL
SELECT
2 AS Tag,
1 AS Parent,
NULL AS "Person!1!Name",
PersonId AS "Person!1!PersonId",
Item AS "Orders!2!Item"
FROM Orders
ORDER BY "Person!1!PersonId"
FOR XML EXPLICIT, ROOT('People')
The first thing to note with this query, is the two columns “tag” and “parent”. You must specify these columns in order to use FOR XML EXPLICIT. These columns specify the hierarchy of your results. The first query will have a “tag” of 1, and a NULL “parent”, as it is the first object declared. Each subsequent “tag” and “parent” will then go up by increments of 1.
Another thing to note, is the column names. The value listed before the first exclamation in the column name specifies the Element Name. The value listed before the second exclamation is the “tag” that it relates to. Then the attribute name is specified. ElementName!TagNumber!AttributeName.
Lastly, it’s the ORDER BY "Person!1!PersonId" that really gives the final result its correct structure.
The XML outputted by the query specified above is as follows:
<People>
<Person Name="Zach Stagers" PersonId="1">
<Orders Item="Bike" />
<Orders Item="Laptop" />
<Orders Item="Phone" />
<Orders Item="Keyboard" />
<Orders Item="Mouse" />
<Orders Item="Pizza" />
</Person>
<Person Name="Libbie Coulson" PersonId="2" />
</People>
As with RAW and AUTO, the ROOT() simply specifies the name of the root element. This is optional.
Without the aforementioned ORDER BY clause, all of the orders for person “Zach” would appear under “Libbie” as she is last in the list, and the UNION ALL will just tack the results from the second query to the end of the result. Ordering by the key between the two tables ensures that the orders against PersonId 1 appear under the person with PersonId 1.
As I mentioned earlier in this post, what really helped me understand what was happening with FOR XML EXPLICIT was seeing the results in there tabular format. To do this, simply remove the FOR XMLline and re-run the code. In the below tabular example, I’ve removed FOR XML EXPLICIT, ROOT('People') from the query:
