This page https://msdn.microsoft.com/en-us/library/ms188276.aspx indicates that if you wanted nested XML (ie an XML Tree) then you need to setup your query like this:
SELECT Col1,
Col2,
( SELECT Col3, Col4
FROM T2
WHERE T2.Col = T1.Col
...
FOR XML AUTO, TYPE )
FROM T1
WHERE ...
FOR XML AUTO, TYPE;
(Using a subquery)
This is exactly at odds with the requirements of an Indexed View (no subqueries allowed).
Is there anyway to get these two features together? (Have an indexed view that has an XML Tree?)
The short of my question is: How can I create an XML Tree (ie nested XML nodes) from many tables without using any subqueries or unions. (So it will work with an SQL Server Indexed View.)
FYI: Not sure if it matters, but my specific query has over 10 levels of my xml tree (pulled from a bunch of different tables).
Best Answer
Short answer: You can't.
Long answer:
There's a few things going on here.
First, you might be underestimating the power of
XML AUTO
. It will provide a certain amount of nesting "automatically". Your provided example, in fact, could be handled without the nested XML generation.Let's make some test tables and data:
Your query:
Produces the same results as one without any nesting:
They both produce:
(That will break down if you have more complex or custom nesting requirements.)
Regardless of this particular example, I don't think there's an effective way to get (dynamic) XML into an indexed view.
First, an "indexed view" is really a view with a unique clustered index. You can't create "normal" indexes on an XML column.
Let's say you try:
You will get an error:
What about an XML index? Well:
CREATE XML INDEX (Transact-SQL)
So in order to have the XML materialized using a view, it can't be the only column. You need a "normal" column to create the unique clustered index on. One way to get a normal column would be to have the XML be created with a subquery. But as you point out, if you try this:
You will get this error:
You might think you could cheat by creating an outer view which didn't have a subquery, calling the original view. But if you try:
You will get an error:
So you can't nest these views, and you can't use subqueries. You can't use the APPLY operator either, so you can't use a table-valued user-defined function (nor can you effectively use the
nodes
XML function).But you can use deterministic scalar-valued functions. So you can construct some rudimentary XML. For example:
While you could create complex, multi-level XML within the function, the function cannot reference any tables (or it wouldn't be deterministic). For example, this:
Results in this error:
Therefore the function can't go get the information it needs. It must be fed the information. And there's simply no way (that I can think of) to collect the data from multiple rows and feed it to the function. You can feed a deterministic function XML to manipulate, but you can't create the base XML without a subquery.
So in short, I don't think there's any way using an indexed view to materialize XML which contains data from multiple rows in any table.