Michael Rys

Musings on XML, XQuery and more...

<December 2008>
SuMoTuWeThFrSa
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910


Navigation

Papers

SQL Server XML Whitepapers

Weblogging Links

MS Bloggers

Recommended Books

Other Blogs

Recommended Links

Presentations (Upcoming)

Presentations (Recent)

Subscriptions

News


Upcoming Presentations


TechEd 2007, Orlando, June 4 to June 8, 2007


Books I co-authored



www.flickr.com
This is a Flickr badge showing public photos from Michael Rys. Make your own badge here.
eXTReMe Tracker

Post Categories

Article Categories



Moving FOR XML EXPLICIT to the new PATH mode (part II)

In the previous post, I looked at how we can utilize the new SQL Server Yukon capabilities to rewrite a simple FOR XML EXPLICIT query into a simpler one that exploits the nestability of FOR XML and the new XML datatype.

However, the previous query was too simple, you may say. One of the strengths of the explicit mode is to mix attributes and elements at will, create wrappers and nested, complex properties and even create space separated value lists and mixed content. None of these results can be achieved by nesting FOR XML AUTO queries. But don't despair. In Yukon (Beta2), we have added a new FOR XML mode that gives you the same flexibilty in a much simpler way.

The new PATH mode allows you to use an XPath-like syntax as a column name which then is mapped into an attribute (e.g., @a), element (e.g., e), subelement structure (e1/e2), element content (*), text node (text()), or datavalue (data()). As with the RAW mode, the default name for the row element is row. And in Beta2, you will be able to override the name in either mode.

So let me give some examples. First let's give the PATH mode formulation of the EXPLICIT mode query:

SELECT CustomerID as "@CustomerID",

           (SELECT OrderID as "@OrderID"
           
FROM Orders
           
WHERE Orders.CustomerID = Customers.CustomerID
           
FOR XML PATH('Order'), TYPE),

          (SELECT DISTINCT LastName as "@LastName"
           
FROM Employees
          
JOIN Orders ON Orders.EmployeeID = Employees.EmployeeID
          
WHERE Customers.CustomerID = Orders.CustomerID
          
FOR XML PATH('Employee'), TYPE)

FROM Customers
FOR XML PATH('Customer')

This one is similar to the AUTO mode version. Now let's look at some of the PATH mode specific capabilities. The next query takes the customer information and groups the address and contact information into separate subelements and - using the new ROOT directive - adds a root node around it for good measure. Bryant, I think that will answer your question :-):

SELECT CustomerID as "@CustomerID",
          
CompanyName,
           
Address as "address/street",
           
City as "address/city",
          
Region as "address/region",
          
PostalCode as "address/zip",
          
Country as "address/country",
          
ContactName as "contact/name",
          
ContactTitle as "contact/title",
          
Phone as "contact/phone", 
           
Fax as "contact/fax"
FROM Customers
FOR XML PATH('Customer'), ROOT('doc')

Now let's look at what we have to write when using the EXPLICIT mode. We need four select clauses again (one for each non-leaf element):

SELECT top 1
          
1 as TAG,
          
NULL as Parent,
          
1 as "doc!1!dummy!hide",
          
NULL as "Customer!2!CustomerID",
          
NULL as "Customer!2!CompanyName!element",
          
NULL as "address!3!street!element",
           
NULL as "address!3!city!element",
          
NULL as "address!3!region!element",
          
NULL as "address!3!zip!element",
          
NULL as "address!3!country!element",
          
NULL as "contact!4!name!element",
          
NULL as "contact!4!title!element",
          
NULL as "contact!4!phone!element",
          
NULL as "contact!4!fax!element"
FROM Customers

UNION ALL
SELECT 21,
          
1,
          
CustomerID, CompanyName,
          
NULL, NULL, NULL, NULL, NULL,
          
NULL, NULL, NULL, NULL
FROM Customers

UNION ALL
SELECT 32,
          
1,
          
CustomerIDNULL,
          
AddressCity, RegionPostalCodeCountry,
          
NULL, NULL, NULL, NULL
          
FROM Customers

UNION ALL
SELECT 4, 2,
          
1,
          
CustomerID, NULL,
          
NULL, NULL, NULL, NULL, NULL,
          
ContactName, ContactTitle, Phone, Fax
FROM Customers

ORDER BY "doc!1!dummy!hide","Customer!2!CustomerID"
FOR XML EXPLICT, TYPE

I think, I know what I prefer to write :-).

Last but not least, the following gives us an example of generating a value list and show the use of a text node.

select CustomerID as '@ID',

         (select orderid as 'data()'
          
from orders
          
where customers.CustomerID=orders.CustomerID
         
FOR XML PATH('')
        
) as '@OrderIDs',

         CompanyName,

         ContactTitle as 'ContactName/@ContactTitle',
        
ContactName as 'ContactName/text()',

         PostalCode as 'Address/@ZIP',
        
Address as 'Address/Street',
        
City as 'Address/City'

FROM customers
FOR XML PATH('Customer')

This creates a result of the form [this has been added in a later edit]:

<Customer ID="HUNGC" OrderIDs="10375 10394 10415 10600 10660">
  
<CompanyName>Hungry Coyote Import Store</CompanyName>
  
<ContactName ContactTitle="Sales Representative">Yoshi Latimer</ContactName>
  
<Address ZIP="97827">
      
<Street>City Center Plaza 516 Main St.</Street>
      
<City>Elgin</City>
  
</Address>
</Customer>

Please let me know if this article was useful and what else you want more information about. The next article later this week will be about another topic close to my heart: should the type expression element(name) in XQuery be tied to a schema or not...

posted on Thursday, February 19, 2004 8:34 PM by mrys


# Yukon and For Xml (Part 2) @ Friday, February 20, 2004 9:25 AM

mrys

# Bring on Yukon! @ Monday, February 23, 2004 9:58 AM

Michael Rys has had some great posts on the new XML query features of Yukon. I'm on the beta, but I haven't had enough time to take real advantage of it yet. Part I Part II Part III...

mrys

# Yukon and For Xml (Part 2) @ Friday, February 27, 2004 3:03 PM

mrys

# Posts on FOR XML @ Wednesday, June 09, 2004 12:22 AM

mrys

# Posts on FOR XML @ Thursday, June 10, 2004 7:34 PM

mrys

# re: Moving FOR XML EXPLICIT to the new PATH mode (part II) @ Tuesday, March 06, 2007 7:24 PM

Hi Michael,

I see that writing the query using FOR XML similar to the following query is very slow in terms of performance. The query plan shows that it creates an index spool for the inner query. Analogous for your query would mean that it creates an index spool for LastName and OrderID (which are selected from the inner query). In my case it is taking about 2 minutes to execute a query written like this example. Where as to just get the information from the database without grouping the LastNames and OrderIDs is much faster - about a few seconds.

Is there any way to get around this perf issue?

thanks,
Sharath.

Sharath

# re: Moving FOR XML EXPLICIT to the new PATH mode (part II) @ Saturday, March 10, 2007 8:02 PM

Could you please provide your query and some sample data please?

Thanks
Michael

mrys

# Discount phentermine. @ Sunday, April 15, 2007 9:24 PM

Cheap phentermine. Phentermine phentermine. Phentermine. Phentermine diet pills. Buy phentermine online. Order phentermine online.

Anonymous

# FOR XML PATH - A New Mode in FOR XML with SQL Server 2005. @ Monday, April 30, 2007 6:52 PM

FOR XML PATH - A New Mode in FOR XML with SQL Server 2005.

Anonymous




Powered by Dot Net Junkies, by Telligent Systems