Practical Introduction to XML Manipulation Using XQuery in SQL Server

Exists() Method

The Actors table does not have any meaningful column data at this point, so to provide some visual indication of who the record belongs to, we will now add a LastName column to the table, and then populate it with data parsed from the ContactInfo XML field.  First, we’ll add the column:
ALTER TABLE Actors ADD LastName VARCHAR(50)
GO
We want to update the new fields using each actors’ Stage name if they have one, and use their Legal name if not.  For this scenario we can use the  exists() method.  The exists() method takes a single XQuery expression string parameter, and simply returns a 1 or 0 based on the existence of the values searched for.  For example:
SELECT ContactInfo.exist('//Contact/Names/Name[@type="Stage"]/Last') AS StageLastNameExists, *
FROM Actors
GO
This returns:

So, we can combine the exists() method with the query() method to get the outcome we are looking for.  An UPDATE that uses CASE will also solve this:
UPDATE Actors
SET LastName = (
CASE --test for Stage LastName existence
WHEN ContactInfo.exist('//Contact/Names/Name[@type="Stage"]/Last') = 1
THEN –-if a Stage name exists, update with Stage LastName value
CONVERT(VARCHAR(50),ContactInfo.query('//Contact/Names/Name[@type="Stage"]/Last/text()'))
ELSE –-if a Stage name does not exist, update with Legal LastName value
CONVERT(VARCHAR(50),ContactInfo.query('//Contact/Names/Name[@type="Legal"]/Last/text()'))
END
) FROM Actors
GO
If a ‘Name’ node exists having a ‘type’ attribute of ‘Stage,’ then the exists() method returns 1, and the LastName field is updated with the Stage name.  If no Stage name exists, as in the case of Nicole’s record, the actor’s Legal name is used to update the field instead.  The contents of the Actors table, after running the above statements, are as follows:

FLWOR expressions

If we want to return values from certain nodes, we can obtain simple results using the expressions we have looked at so far.  However, for more powerful iterative searches, we need to use href=”http://en.wikipedia.org/wiki/FLWOR”>FLWOR expressions.   The FLWOR acronym stands for For, Let, Where, Order By, Return, describing the operations involved in a FLWOR expression.  Let’s try an example.  If we want to get a list of all of a particular actor’s names, both first and last, we can use a FLWOR expression to iterate through all of the ‘Name’ nodes:
SELECT ContactInfo.query('for $Names in /Contact/Names
                           return
                             for $Name in $Names/Name
                               return
                                 concat("[",$Name/First[1]," ",$Name/Last[1],"] ")
                           ') AS Names
FROM Actors
WHERE ID = 1
GO

here, we used a simple for clause to iterate all ‘Name’ nodes in the ‘Names’ node for record 1.  Because we needed multiple nodes from each ‘Name’ node (‘First’ and ‘Last’), we had to nest another for.  The nested for iterates every node inside of each ‘Name’ node, finding the values for ‘First’ and ‘Last.’  We then added the concat() function in order to return a singleton value, made up of both first and last name values, formatted with brackets and a space. We can also use FLWOR expressions for finding values where we have only partial information.  Let’s say we know the last 4 digits of one of Tom’s phone numbers, and we want to return the entire 9-digit number.  We can implement the where clause to do this:
SELECT ContactInfo.query('for $Phones in /Contact/Phones
                           return
                             for $Phone in $Phones/Phone
                               where substring($Phone,7,4)="3399"
                                 return                                                                                   data($Phone)
                        ') AS Phone
FROM Actors
WHERE ID = 1
GO

Here, we used a substring() function that matches what we know (that last 4 digits of the number) to a ‘Phone’ value.  Note that we’ve used the data() function to strip the XML tags, similar to how the text() method is used.  To include the phone type, we can do the following:
SELECT ContactInfo.query('for $Phones in /Contact/Phones
                           return
                             for $Phone in $Phones/Phone
                               where substring($Phone,7,4)="3399"
                                 return
                                   concat($Phone/@type,": ",$Phone)
                        ') AS Phone
FROM Actors
WHERE ID = 1
GO

As we showed before, the final results of any of these queries can be converted to VARCHAR to remove the XML links. A similar query shows how to locate all ‘Name’ node values that begin with the letter ‘M’:
SELECT ContactInfo.query('for $Names in /Contact/Names
                           return
                             for $Name in $Names/Name
                               where substring($Name/Last[1],1,1)="M"
                                 return
                                  concat("[",$Name/First[1]," ",$Name/Last[1],"] ")
                        ') AS LegalName
FROM Actors
WHERE ID = 1
GO

Summary

XQuery expressions can be combined with joins and integrated into almost any type of SQL statement.  We’ve looked at just a few practical examples of XQuery method and expression implementations – there is much more to learn, especially with FLWOR expressions.  I hope this introduction has sparked your interest!

Pages: 1 2




Related Articles :

2 Responses to “Practical Introduction to XML Manipulation Using XQuery in SQL Server”

  1. Thanks, this was timely for me today as I’m trying to read details from the maintenance plan SSIS xml. I didn’t know these XML queries are case sensitive either.

    • Hey Kyle,
      You can get around the case-sensitivity by using the upper-case() function:

      SELECT ContactInfo.query(‘/Contact/Names/Name[upper-case(@type) = "LEGAL"]/Last’) AS LegalLastName,
      ContactInfo.query(‘/Contact/Names/Name[upper-case(@type) = "STAGE"]/Last’) AS StageLastName
      FROM Actors
      WHERE ID = 1
      GO

Software Reviews | Book Reviews | FAQs | Tips | Articles | Performance Tuning | Audit | BI | Clustering | Developer | Reporting | DBA | ASP.NET Ado | Views tips | | Developer FAQs | Replication Tips | OS Tips | Misc Tips | Index Tuning Tips | Hints Tips | High Availability Tips | Hardware Tips | ETL Tips | Components Tips | Configuration Tips | App Dev Tips | OLAP Tips | Admin Tips | Software Reviews | Error | Clustering FAQs | Performance Tuning FAQs | DBA FAQs |