Professional Documents
Culture Documents
Learn Xquery in 10 Minutes, SQL Server 2005 Style: What Is Xquery For?
Learn Xquery in 10 Minutes, SQL Server 2005 Style: What Is Xquery For?
I always love reading the works of Dr. Michael Kay. He recently posted what I thought was a really
good introduction on XQuery over on the Stylus Studio site
(http://www.stylusstudio.com/xquery_primer.html.) But being the SQL Server 2005 fanatic that I
am, I couldn’t help but notice he didn’t give the product any love. So for those you using (or will
soon be using) SQL Server 2005 and XQuery, I’m happy to present this quick guide to XQuery,
SQL Server 2005 style.
In many ways, XSLT and XQuery give you different ways to achieve the same result with neither
always being “better.” A big difference for us as SQL Server 2005 users is that XQuery is
implemented as actual part of the Query Processing engine so it take advantage of indexing and type
inference from schemas. This provides for optimized query processing. You can do XSLT
transformations fairly easily with a SQLCLR function, but this won’t leverage indexes or schema
collections.
As Dr. Kay notes in his work, if you have to install anything, it is going to take more than ten
minutes, so feel free to just read along if you like.
sqlcmd –S .\sqlexpress –E
And yes, the –S and –E do need to be capitalized. This will start the SQLCMD utility, an easy to use
interface that lets you submit queries to SQL Server 2005. The “-S .\sqlexpress” option tells
SQLCMD that you want login into the local instance of SQL Server 2005 Express Edition while the
–E option says you want to use Windows Integrated Security. After doing all of that you should be
greeted with “1>” prompt. At that prompt type each of the following lines in individually, pressing
enter at the end of each line.
set quoted_identifier on
declare @x xml
set @x='<?xml version="1.0" ?><p>Hello, World!</p>'
select @x.value('(/p)[1]','varchar(max)')
go
When you’re done, your screen should look something the following:
1. set quoted_identifier on: This is required for SQLCMD to properly understand line 4.
2. declare @x xml: This declares a variable, named “@x,” using the new XML data type.
3. set @x='<?xml version="1.0" ?><p>Hello, World!</p>': This populates the variable with
the XML of interest. Under the covers, SQL Server discards the document prolog and just
stores the <p> tag and the text in a fast binary form in memory.
4. select @x.value('(/p)[1]','varchar(max)'): There’s actually quite a bit of work going on
here. First, we’re executing a select T-SQL query. We have to do this because our XML is
stored in a T-SQL variable. In fact, almost all access to XML data type instances in SQL
Server requires us to access the instance via T-SQL. Why? As previously noted, SQL Server
2005 XQuery process is integrated with the T-SQL query processor. Next we invoke the
value method on variable. Unlike many other T-SQL Data Types, the XML Data Type is
primarily worked with using methods on instances. SQL Server 2005 engine processes the
queries within these method calls as XQueries. The value method takes an XQuery which
returns a scalar result and then type casts that to the second parameter to the method call. In
this case, we’re making a simple XPath query over the stored data (which is fine, XQuery is
a superset of XPath) with the “/p” part of the expression. We wrap this in parentheses to
indicate that the query returns a sequence of values. Finally we tack on the “[1]” part to
indicate that we want the first value from the sequence. The “varchar(max)” actual parameter
indicates that we want the value returned by the query returned as a string.
5. go: This simply tells SQLCMD to transmit the command to server and display and response
returned.
And I’ll agree with Michael, we’re not pushing the envelope of Rocket Science, but we have already
covered the primitives of the XQuery usage pattern: write a T-SQL query that invokes one or more
of the methods of the XML data type. We pass an XQuery into the query processor as parameters of
one of these methods.
1. Download this file. It will create a custom database, a table and will populate a table with the
videos.xml file. Save this file to “C:\”
2. If you are still in the SQLCMD shell, type exit to return to the DOS prompt.
3. At the command prompt type:
sqlcmd -S .\sqlexpress -E -i xqueryin10minutes.sql -h -1
This particular version of the SQLCMD invocation uses the –i option to run the download script.
The output of this command should look like this:
Now if you’re comparing this along side Dr. Kay’s tutorial, you’re probably expecting me to show
you the “find all actors with a first name of Lisa query.” We can do that, but keep in mind that SQL
Server 2005 doesn’t currently support the ends-with function he uses. There are a few more
functions that are missing. The downloadable “Books On Line” talks about them. We can, however,
show a similar search using contains. For example, enter this at the SQLCMD 1> prompt:
1. select actors.actor.value('.','varchar(max)')
2. from dbo.videos
3. cross apply list.nodes('.//actor') as actors(actor)
Wow, there’s a lot goes in this relatively short query! This is because we are taking a part of single
document and breaking it into rows using the node so let’s break it down line by line to see what
each part means.
1. This line uses the value method on the “actor” field in the “actors” virtual table created on
line three. The key point here is that the virtual table has exactly one row for each actor
element in our document, so we need to reference the whole virtual table to access its rows
and thus values.
2. This simply tells the query to use the videos table in the dbo schema.
3. This line does three main things. First, we use cross apply to include the results of functions
called on part to the data consumed in the from statement. The called to the nodes method
here simply creates a virtual table with one row for each node matching the XQuery
statement passed into the method call. In this case, we’re looking for any elements named
“actor”. The last part, starting with the as, defined the virtual table name and column name.
4. Finally, the where predicate filters rows out the virtual table. We’re using another XQuery
here as an actual parameter to the value method. In this case, we’re calling the Contains
function. This function simply tests to see if the text passed as the second actual parameter to
that method exists in the text value of the node indicated in the first part. In this case, we’re
looking to see if the string “ Lisa” (and yes, it’s case sensitive), exists in the text part of an
“actor” element.
1. declare @n xml
2. select @n = list.query('
3. for $video in (.//video)
4. for $actor in (.//actor)
5. where $video/actorRef/text() = $actor/@id
6. and contains(($actor/text())[1],sql:variable("@actor"))
7. order by ($video/title/text())[1]
8. return <v>{$actor/text()} was in "{$video/title/text()}"</v>')
9. from dbo.videos
We start by declaring that “@n” will be an XML typed variable. Line two sets that value of the
variable to the result an XQuery. Lines three through eight represent an XQuery in what is known as
FWOR notation. As we talked about earlier, XQuery is a superset of XPath, so almost any XPath
expression is also a valid XQuery. However, XQuery has another allowed syntax, using a pattern of
F(or), W(here), O(rder) and R(eturn). It works as you might expect: each of the “for” exposes the
nodes selected in the following XPath expression for use as a variable. In this case, on lines three
and four, we will have two sequences of values to work with: $video representing each of the
“video” elements in the documents while $actor represents each actor element in the document.
Another SQL-like concept that XQuery provides in FWOR queries is the ordering of results using
“order by.” The essential different with XQuery is that instead of specifying a column name, you
provide it with an XPath expression that returns a scalar value. For our example, line seven simply
selects the text value of the video title element.
The last part of our XQuery is the return on line eight. XQuery’s return is pretty easy to understand.
Anything that is not wrapped in curly-braces (e.g., { and }) is output directly (and unevaluated) into
the sequence returned by the XQuery. Anything wrapped up in curly-braces is evaluated as a
statement and the resulting value will be emitted into the resulting sequence as literal values.
So let’s see this stored procedure in action. If you still have SQLCMD open, you can simply type the
following query in:
Now, you might asking why I didn’t call them FLWOR expressions or talk about the L(et) part of
XQuery. This is one of another one of these cases where SQL Server 2005 doesn’t fully implement
the XQuery working drafts – there’s simply no support for the Let construct at all.
1. select list.query('
2. for $video in (.//video),$actor in (.//actor)
3. where $video/actorRef/text() = $actor/@id
4. and contains(($actor/text())[1],sql:variable("@actor"))
5. order by ($video/title/text())[1]
6. return <li>{$video/title/text()}</li>')
7. from dbo.videos
8. for xml path(''),root('ul'),type
Lines one through five and seven are little changed since our last example, so I won’t detail them
here again. Line six, however, is. Here we are using XQuery’s ability to emit literal values to
generate XML tags (the <li> and </li> strings) around our data. Line eight shows using a FOR XML
extension to the T-SQL select to generate XML. In this case, we’re using the path option, but since
all our elements – the sequence generated by the XQuery – already represents full-formed elements,
we don’t need to specify any element names for it to wrap our values with. We simply ask it to emit
an empty string instead. The Root part then wraps all of the elements from the XQuery into a single
XML element named “ul.” Finally, the type part tells SQL Server that we returning an SQL Server
style XML instance. You can test this stored procedure out just by calling
dbo.VideosWithActorsWithNamedAsXML as shown following:
Time Is Up!
We’ve covered a lot of ground in this article: you’ve seen how you can get started using XQuery
with SQL Server 2005 Express edition and the SQLCMD utility. The key things to remember are:
• To use XQuery within SQL Server 2005, you write T-SQL queries that call methods on
XML-typed instances on columns and/or variables.
• The commonly used methods are Query, which returns the sequence of values directly as part
of a result set; Value, which converts the returned sequence as a T-SQL scalar value type and
Nodes, which parses a single XML instance into a virtual table split on a given XPath
expression.
• XQuery is a superset of XPath. Almost all XPath expressions are also valid XQuery
expressions. XQuery in SQL Server 2005 also offers the FWOR pattern syntax – For, Where,
Order and Return – which can simply writing XML transformations.
If you’re interested in learning even more about XQuery in SQL Server 2005, there are a number of
resources I highly recommend, including:
• The SQL Server 2005 Books On Line covers many of the technical details of using XQuery
in a reference format style.
• Dr. Michael Rys’s Webcast on using XQuery at http://url123.com/dgs47
• The book A First Look at SQL Server 2005 for Developers by Beauchemin, Berglund and
Sullivan has excellent coverage of both the XML Data Type and XQuery.