Blog By Hal Hayes
Wednesday, September 14, 2005

Here is something that we as developers should be aware of in working with an XQuery statement (.query on an XML datatype) in SQL Server 2005: if a Where clause returns false, then you may end up with an empty xml data type. I believe this would return an empty string if you are using ADO (I'll try it later).

I asked Michael Rhys about this in his presentation on XQuery at PDC. He said that since you are selecting on an XML column with the query operation, you must return something - even if the XQuery statement itself returns nothing - UNLESS you check the existence in the Transact SQL Where clause.

Here is an example of the problem:

-- Create a table with an XML column

CREATE TABLE customerData(
    ID int IDENTITY(1,1) NOT NULL,
    customerDocs xml NOT NULL,
    updated datetime NOT NULL DEFAULT (getdate()),
CONSTRAINT [PK_customerData] PRIMARY KEY CLUSTERED
(
    [ID] ASC
) ON [PRIMARY]
) ON [PRIMARY]
GO

-- Let's add some data
INSERT INTO customerData(customerDocs)
    VALUES(N'<?xml version="1.0"?>
    <customers>
        <customer name="bob" status="current"/>
        <customer name="sally" status="no order FY2005"/>
        <customer name="judy" status="no order FY2004"/>
        <customer name="mark" status="current"/>
    </customers>'
)
GO

-- Let's view it
SELECT * FROM customerData
GO

The results will be something like this:

2 <customers><customer name="bob" status="current" /><customer name="sally" status="no order FY2005" /><customer name="judy" status="no order FY2004" /><customer name="mark" status="current" /></customers> 2005-09-14 09:05:20.780

Here is an XQuery statement that has a valid where clause:

SELECT customerDocs.query('
for $CUSTOMER in //customer
    where $CUSTOMER/@status eq "current"
    return $CUSTOMER'
) AS RESULTS
FROM customerData

This returns an XML data type

<customer name="bob" status="current" /><customer name="mark" status="current" />

But what about this XQuery statement for which the where clause is false:

SELECT customerDocs.query('
for $CUSTOMER in //customer
    where $CUSTOMER/@status eq "NOT current"
    return $CUSTOMER'
) AS RESULTS
FROM customerData

The return value is an empty XML data type!!! This may not be what developers are expecting.

Michael Rhys suggested that the best practice for an XQuery that have a false where clause is to put an exists condition in the outer Transact SQL where clause, like this:

SELECT customerDocs.query('
for $CUSTOMER in //customer
    where $CUSTOMER/@status eq "NOT current"
    return $CUSTOMER'
) AS RESULTS
FROM customerData
WHERE
    1 = customerDocs.exist('//customer[@status eq "NOT current"]')

This will return an empty record set, rather then an a record set with an empty XML type, if there is no data within the XML document that satisfies the where clause.

 

9/14/2005 10:45:19 AM (Eastern Daylight Time, UTC-04:00) |  | PDC | SQL Server 2005 | XQuery#
Search
Archive
Links
Categories
Admin Login
Sign In
Blogroll
 CTO 2.0
Antonio Chagoury
Dot NET Ramblings
Brian Noyes
 New Entry
 SharePoint Resources
Lamont Harrington
 Winsmarts
Sahil Malik
Themes
Pick a theme: