Vanguard Appraisals, Inc. CAMA-X Advanced Query Wizard And ...
X Query
Transcript of X Query
Microsoft SQL Server 90 Technical Articles
Introduction to XQuery in SQL Server 2005
Prasadarao K VithanalaMicrosoft Corporation
June 2005
Summary This white paper provides an introduction to various features of XQuery implemented in SQL Server 2005 suchas the FLWOR statement operators in XQuery if-then-else construct XML constructors built-in XQuery functions typecasting operators and examples of how to use each of these features Non-supported features of XQuery in SQL Server2005 and workarounds are described in this article It also presents three scenarios where XQuery is useful (30 printedpages)
Contents
IntroductionThe XML Data Type in SQL Server 2005Introduction to XQueryStructure of the XQuery ExpressionOperators in XQueryThe if-then-else ConstructConstructing XML Using XQueryBuilt-in XQuery FunctionsType-Related ExpressionsAccessing Relational Columns and VariablesNon-Supported Features and WorkaroundsBest Practices and GuidelinesXML Data ModificationXQuery Usage ScenariosConclusion
Introduction
XML was developed for use as a document format However the additional features of XML such as extensibility supportfor internationalization the ability to represent both structured and semi-structured data and easy readability by humansand machines have rendered XML an immensely popular platform-independent data representation format As XML gainswide acceptance users apply XML to solve complex business problems such as those involving data integration There aremany scenarios where it is recommended that information be stored in XML format rather than to store it in tables andthen compose XML messages from the information For more information about these scenarios see the MSDN article XMLBest Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] Theapplication of XML for storing documents and for representing semi-structured data has led to the evolution of XML as adata storage format that simplifies data management at the server
This evolution however posed a problemmdashextracting information from the XML data stored in relational tables as BLOBsrequired a query language to extract and shape information represented in the XML Microsoft SQL Server 2000 providedOpenXML which could be used for querying but was designed for mapping XML data to relational form and thus could notprovide full support for the XML data model (see Table 1)
The relational data model and the XML data model differ in a lot of ways The following table outlines the major differencesbetween the two data models
Table 1 Differences between the relational and XML data models
copy2007 Microsoft Corporation All rightsreserved
Feature Relational Data ModelXML DataModel
Flat structured data Uses flat tables to store data in a column formRecommended way to store flat structured data
Useful when itis required topreserve thedocumentorder or whenthe schema isflexible orunknown
Semi-structured data It is difficult to model semi-structured data usingrelational model
Providesexcellentsupport for
Both the increasing need to deal with more heterogeneously structured data and the necessity of having an implied orderare two of the most important reasons why the relational data model is being extended to store XML documents nativelyIn addition the limitations of the SQL language in handling semi-structured or markup information resulted in thedevelopment of the XQuery language The XQuery language has been designed from scratch taking into consideration thenature of XML data and the issues involved in processing it
SQL Server 2005 has built-in support for the native storage of XML data using the XML data type XQuery 10 is alanguage that is being defined by the World Wide Web Consortium (W3C) XML Query Working Group to formulate queriesover XML data XQuery like SQL is a declarative query language that as we will see later can be easily understood witha basic knowledge of SQL and XPath
This paper is based on the implementation of XQuery 10 in SQL Server 2005 which in turn is based on the XQuery 10July 2004 working draft The first section of this paper provides an overview of the new XML data type and its associatedfeatures Subsequent sections introduce the new XQuery language and its advantages the FLWOR statement variousoperators in XQuery built-in functions in XQuery type-related expressions and non-supported features in SQL Server2005 respectively Finally the last sections provide information on best practices and guidelines XML data modificationand XQuery usage scenarios
The XML Data Type in SQL Server 2005
The new XML data type introduced in SQL Server 2005 provides users with the ability to store XML documents andfragments in the database An XML data type can be used to create a column a parameter to a stored procedure orfunction or a variable
Additionally the user can associate a column of type XML with an XML schema collection to create a typed XML columnThe XML schemas in the collection are used to validate and type the XML instances
Typed vs Untyped XML Data Type
An XML data type can be associated with an XML schema collection to have schema constraints enforced on XMLinstances If the XML data is associated with an XML schema collection it is called typed XML Otherwise it is calleduntyped XML
The SQL Server 2005 XML data type implements the ISO SQL-2003 standard XML data type It can store not only well-formed XML 10 documents but also so-called XML content fragments with top-level text nodes and an arbitrary numberof top-level elements Checks for well-formedness of the data are performed and these checks do not require the XMLdata type to be bound to XML schemas Data that is not well-formed (subject to the SQL-2003 content relaxations) isrejected
Untyped XML is useful when the schema is not known a priori It is also useful when the schema is known but changingrapidly and thus hard to maintain or multiple schemas exist and are late bound to the data based on externalrequirements Furthermore untyped XML is useful when the XML schemas contain XML Schema constructs not supportedby the database engine (eg keykeyref lax validation) In that case you could use the SystemXML validator inside aCLR (common language runtime) user-defined function to provide validation
If you have XML schemas in an XML schema collection describing your XML data you can associate the XML schemacollection with the XML column to yield typed XML The XML schemas are used to validate the data perform more precisetype checks than untyped XML during compilation of query and data modification statements and optimize storage andquery processing
representingsemi-structured datawith variable orevolvingschema
Markup data Not suitable for storing markup data beyondBLOB storage
Excellent forstoring markupdata such asHTML RTF andso on
Nested or hierarchical data structures Supports nested data by using multiple tablesand linking them with foreign keys but thecomplexity of queries required for searchingnested data stored in relational form increaseswhen the depth of nesting increases or isunknown
Providesexcellentsupport forexpressingnested andhierarchicaldata
Order of data Not preserved Preserved
Input data Homogeneous Heterogeneous
Result set Homogeneous Heterogeneous
Typed-XML columns parameters and variables can store XML documents or content fragments which you can specify asan option (DOCUMENT or CONTENT respectively with CONTENT as the default) at the time of declaration Furthermoreyou have to provide the collection of XML schemas Specify DOCUMENT if each XML instance has exactly one top-levelelement otherwise use CONTENT The XQuery compiler uses the DOCUMENT flag information to infer Singleton top-levelelements during static type inference
Methods of the XML Data Type
The XML data type supports five methods that can be used to manipulate XML instances The methods of the XML datatype can be described as follows
The query() method takes an XQuery expression that evaluates to a list of XML nodes and allows the user to extractfragments of an XML document The result of this method is an instance of untyped XML
The value() method is useful for extracting scalar values from XML documents as a relational value This method takes anXQuery expression that identifies a single node and the desired SQL type to be returned The value of the XML node isreturned cast to the specified SQL type
The exist() method allows the user to perform checks on XML documents to determine if the result of an XQueryexpression is empty or nonempty The result of this method is 1 if the XQuery expression returns a nonempty result 0 ifthe result is empty and NULL if the XML instance itself is NULL
Decomposing an XML document into relational data is facilitated by the nodes() method of the XML data type The nodes() method accepts an XQuery expression and returns a rowset in which each row represents a context node identified bythe query expression Methods of the XML data type such as query() value() exist() and nodes() can also beinvoked on the context nodes returned from the nodes() method
The modify() method can be used to modify the content of an XML document It accepts XML DML statements to insertupdate or delete one or more nodes from an XML instance It raises an error if applied to a NULL value
For more information see the XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ] white paper
Introduction to XQuery
XQuery is a new language for querying XML data that allows navigational access based on XPath 20 This section providesan overview of various aspects of the XQuery language such as the relationship between XQuery and XPath advantages ofusing XQuery application areas of XQuery the role of XML Schema in XQuery and so on
Overview of XPath 20
XPath 10 [ httpwwww3orgTRxpath ] as defined by the W3C is a language for locating parts of an XML documentXPath uses path-based syntax for identifying nodes in the XML document It also defines the core syntax for both XSLT 10[ httpwwww3orgTRxslt ] and XPointer [ httpwwww3orgTRWD-xptr ] XPath 10 has built-in functions tohandle strings Boolean values and floating point numbers It defines the syntax for filtering the node set with the abilityto specify filtering criteria XPath 10 is being extended in XPath 20 [ httpwwww3orgTRxpath20 ] to support amore detailed type system and to provide more functionality XQuery 10 [ httpwwww3orgTRxquery ] in turn isbased on XPath 20 and adds ordering reshaping construction and validation capabilities to the navigational and filteringaspects of XPath 20
Overview of XQuery
XQuery is a declarative typed functional language designed from scratch by the XML Query Working Group specifically forthe purpose of querying data stored in XML format XQuery shares the same data model and the same XML Schema[ httpwwww3orgXMLSchema ] -based type system with other members of the XML standards family such as XPath20 and XSLT 20 [ httpwwww3orgTRxslt20 ] XQuery is designed to work with XML documents that are untyped(no schema associated with the data) typed with XML schemas or a combination of both As previously mentionedXQuery 10 is basically a superset of XPath 20 In addition to the features of XPath 20 it has the following capabilities
l Adds an order by clause to the FLWOR clause to sort in non-document order
l Adds a let clause to the FLWOR clause to name results of expressions for further use (not supported in SQL Server2005)
l Provides a way to specify static context items in the query prolog (such as namespace prefix bindings)
l Provides the ability to construct new nodes
l Provides the ability to define user-defined functions (not supported in SQL Server 2005)
l Provides the ability to create moduleslibraries (not supported in SQL Server 2005)
Advantages of XQuery
l It is easy to learn if knowledge of SQL and XPath is present
l When queries are written in XQuery they require less code as compared to queries written in XSLT
l XQuery can be used as a strongly typed language when the XML data is typed which can improve the performanceof the query by avoiding implicit type casts and provide type assurances that can be used when performing queryoptimization
l XQuery can be used as a weakly typed language for untyped data to provide high usability SQL Server 2005implements static type inferencing with support for both strong and weak type relationships
l Because XQuery requires less code to perform a query than does XSLT maintenance costs are lower
l XQuery is going to be a W3C recommendation and will be supported by major database vendors
Caveat regarding XQuery 10 language as of the writing of this document
l The XQuery specification is currently under development and may change in the future SQL Server 2005 implementsa stable part of the W3C working draft
Application Areas of XQuery
Application areas of XQuery can be classified broadly as follows
l XQuery for queryanalysis XQuery is excellent for querying huge chunks of data and provides the capability tofilter sort order and repurpose the required information Typical applications include querying XML documents thatrepresent semi-structured information name-value pair property bags analysis of application logs transaction logsand audit logs to identify potential application errors and security issues and so on
l XQuery for application integration As organizations move away from proprietary application integrationapproaches and start adopting standards based application integration approaches the need for transforming datafrom internal application-specific formats to standard exchange formats is gaining more focus Because of its abilityto construct and transform XML data XQuery caters to this need One typical use of XQuery in the application-integration domain is translating the vocabulary used by one application that uses native XML databaserelationaldata source into a language used by another application that uses XMLrelational data format
Advantages of Using XQuery at the Server
Performing XML processing at the server using XQuery has many advantages compared to client-side XML processingSome of these advantages can be summarized as follows
l Reduced traffic on the network When XML data is processed on the server only the results are forwarded to theclient This results in reduced traffic on the network
l More security Only the data that is required is sent to the client thereby avoiding the risk of exposing the entiredata to the network as is the case when using client-side XML processing
l Better maintainability Processing XML on the server results in browser independent code on the client whichleads to better maintainability on the client side
l Improved performance Queries written using XQuery on the server are subjected to optimization by the SQLquery engine This results in improved performance when compared to retrieving the entire data and filtering thedata at the client Furthermore indexes can be created on the XML data type column to achieve enhancedperformance
How XQuery Implementation Uses XML Schemas
The XML schema collection associated with an XML data type is used by the relational engine as follows
l To validate the XML instances during insertion operations
l To validate the XML instances during modification operations
l Type information contained in the XML schema is used during static type checking for early error detection and forquery performance improvements by generating better query plans and avoiding many runtime inspections
l Type information present in the XML schema is used by the SQL Server to optimize storage
Structure of the XQuery Expression
An XQuery expression in SQL Server 2005 consists of two sectionsmdasha prolog and a body A prolog can in turn contain anamespace declaration subsection Namespace declarations are used to define a mapping between prefix and namespaceURI thereby enabling you to use the prefix instead of the namespace URI in the query body You can also refer to elementnames without the prefix by binding a default namespace for element names using the declare default namespacedeclaration
The body of an XQuery expression contains query expressions that define the result of the query It can for example bethe signature FLWOR expression (see The FLWOR Statement in this paper) an XPath 20 expression (see XPath 20
Expressions in this paper) or another XQuery expression such as a construction or arithmetic expression
Example Specifying default namespace in prolog section of XQuery
The following query selects all Employment nodes for a candidate whose JobCandidateID is 3 The query defines adefault namespace and does not use a namespace prefix
SELECT Resumequery(declare default namespace httpschemasmicrosoftcomsqlserver200407adventure-
worksResumeResumeEmployment
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Specifying namespace using the WITH XMLNAMESPACES clause
SQL Server also supports the SQL-2003 standard extension that allows a user to declare XML namespace bindings in theSQL WITH clause on a per SQL query basis thus avoiding repetitive declarations in multiple XML data type methodinvocations The following query shows the modified version of the query shown in the previous example This querydeclares a namespace using the WITH XMLNAMESPACES clause
WITH XMLNAMESPACES( httpschemasmicrosoftcomsqlserver200407adventure-worksResumeAS RES)SELECT Resumequery(
RESResumeRESEmployment) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
XPath 20 Expressions
XQuery uses XPath 20 expressions to locate nodes in a document and to navigate from one location to another within asingle document or across documents Navigation paths defined using XPath consist of a sequence of steps separated by A single step comprises an axis a node test and zero or more step qualifiers
The axis specifies the direction of movement relative to the context node Supported axes in SQL Server 2005 are childdescendant parent attribute self and descendant-or-self
A node test specifies a condition that all the nodes that are selected by a step must satisfy The node condition can bespecified based on node name or node type
Step qualifiers can be defined by using predicates or dereferences A predicate is an expression that acts as a filter on anode sequence and is specified within square brackets A dereference maps the elements andor attributes nodes in anode sequence to the nodes that they reference A node sequence passed as an input to the dereference must containelements or attributes of type IDREF or IDREFS The dereference generates a new sequence consisting of the elementnodes whose ID-type attribute values match the IDREF values extracted from the elements and attributes in the inputsequence
The steps of an XPath expression are evaluated from left to right Execution of a step sets the evaluation context items forthe next step A context item in a path expression is a node that is selected as a result of the execution of a step in anXPath expression A step is evaluated relative to the context item that was obtained in the previous step The result of anXPath expression is a sequence of nodes in document order that are obtained after executing all the steps in theexpression in the order from left to right in the path expression
This example expression uses the column Resume which is of type XML in table [HumanResources][JobCandidate] fromthe AdventureWorks database for the purpose of illustrating the concept of path expressions The following pathexpression selects all address nodes for which the address type is set to Home
childnsAddrType[=Home]parentnode()
In the preceding path expression
l child is the axis specifier
l is the axis separator
Copy Code
Copy Code
Copy Code
l ns is the namespace prefix
l AddrType is the node test
l [=Home] is the predicate expression where refers to the context node
XQuery also supports abbreviated syntax for specifying the axis The following table shows the axis and correspondingabbreviated syntax
Table 2 Abbreviated syntax for axes
Example Selecting organization names from employment history
The following XPath expression selects the children text nodes of EmpOrgName elements that are child nodes of nodeResumeEmployment Here text() is used to select the text node of the EmpOrgName element
ResumeEmploymentEmpOrgNametext()
The FLWOR Statement
FLWOR statements form the core expressions of XQuery and are similar to the SELECT statements of SQL The acronymFLWOR (pronounced flower) stands for FOR LET WHERE ORDER BY RETURN FLWOR expressions in XQuery enableusers to specify operations such as declarative iteration variable binding filtering sorting and returning the results SQLServer 2005 supports FOR WHERE ORDER BY and RETURN
For
The for clause in a FLWOR expression enables users to define a declarative iteration of a bound variable over an inputsequence The input sequence can be specified using XPath expressions sequence of atomic values a sequenceconstructed using literals or constructor functions It is therefore analogous to the SQL SELECT FROM clause and is notlike a programming language for construct
Variable binding is also specified in the for clause
Example Selecting all home address elements from resume using the for clause
The following query selects all Address nodes where the type of address is set to Home and the JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddressRESAddrType[=Home]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
where
The where clause filters the results of an iteration by applying the expression specified with the where clause
Example Selecting all home address elements using the where clause
The following query selects all Address nodes where the type of address is set to Home and the JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $ARESAddrType[=Home]
Axis Abbreviated form
Attribute
Child
descendant-or-selfnode()
parentnode()
selfnode()
Copy Code
Copy Code
return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
order by
The order by keyword enables you to sort the values in the returned result set The order by keyword accepts a sortingexpression which should return an atomic value Optionally you can also specify ascending or descending for the sortorder The default sort order is ascending
Example Selecting employment history in ascending order using the order by clause
The following query selects all Employment nodes in ascending order of employment starting date for a candidate whoseJobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentorder by $EMPRESEmpStartDatereturn$EMP
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
return
The return clause which is analogous to the SELECT clause in SQL enables users to define the result of a query You canspecify any valid XQuery expression in the return clause You can also construct XML structures in the return section byspecifying constructors for elements attributes etc
Example Selecting specific elements of employment history using the return clause
The following query selects StartDate EndDate OrgName JobTitle elements of Employment node for a candidate whoseJobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentorder by $EMPRESEmpStartDatereturn
ltEmploymentgt $EMPRESEmpStartDate $EMPRESEmpEndDate $EMPRESEmpOrgName $EMPRESEmpJobTitle
ltEmploymentgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Current implementation of XQuery in SQL Server 2005 does not support the let clause This aspect is discussed further inNon-supported Features and Workarounds in this paper
FLWOR Expressions vs XPath Expressions
Using a FLWOR expression to define the result sequence when the sequence can be expressed using an XPath expressionincurs a performance penalty because the query plan contains a JOIN operation between the for variable and the body ofthe for clause The use of a FLWOR expression is justified only if one or more of the following conditions are satisfied
l If you want to iterate over a sequence of values that are returned as a result of an expression This is achieved usingthe for clause which binds a variable to successive values of the result set Examples are the construction of newelements within the scope of the for clause and the retention of duplicates
l When you want to filter the result sequence of the for clause based on a predicate which cannot be defined using
Copy Code
Copy Code
simple XPath expressions The where clause is used to eliminate unwanted values in the result set An example is asfollows
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(for $i in (1 2 3) $j in (3 4 5)where $i lt $jreturn sum($i + $j)) as Result
l If you want to sort the result set based on a sorting expression Sorting is defined on the result set using the orderby clause
l When you want to define the shape of the returned result set using the results obtained from the for clause Thereturn statement is used to perform the shaping of the result set
In all other cases using XPath expressions is recommended
Operators in XQuery
As a functional language XQuery in SQL Server 2005 supports various types of functions and operators that can begrouped under the following categories
l Arithmetic operators
l Comparison operators
l Logical operators
Table 3 Operators supported in SQL Server 2005
Arithmetic Operators
SQL Server 2005 supports five arithmetic operators These are + b div and mod Currently it does not support idiv
Example Converting selected values of store survey information
This example is based on the [Sales][Store] table in the AdventureWorks database The following query returns values ofAnnualSales AnnualRevenue in yen and the store area in square meters for a store whose CustomerID is 3
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyfor $S in STStoreSurveyreturn
ltStoreDetailsSalesInYen = $SSTAnnualSales1068100 RevenueInYen = $SSTAnnualRevenue1068100 StoreAreaInSqMeters = $SSTSquareFeet00929 gt
ltStoreDetailsgt) as ResultFROM [Sales][Store]WHERE CustomerID = 3
Comparison Operators
Copy Code
Type Operators
Arithmetic operators +-div mod
General comparison operators = = lt gt lt= gt=
Value comparison operators eq ne lt gt le ge
Node comparison operator is
Node order comparison operators gtgt ltlt
Logical operators and or
Copy Code
SQL Server 2005 has implemented support for four types of comparison operatorsmdashgeneral comparison operators valuecomparison operators node comparison operators and node order comparison operators
General comparison operators
General comparison operators help compare atomic values sequences or a combination of the two General comparisonoperators are = = lt gt lt= and gt= A general comparison is existentially quantified meaning that any match willresult in true
Example Selecting all address elements where the address type is not set to Home
The following query selects all Address nodes where the type of address is not set to Home and the JobCandidateID is3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $ARESAddrType[=Home]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Value comparison operators
Value comparison operators help compare atomic values Value comparison operators supported by SQL Server 2005 areeq ne lt gt le and ge The current implementation of XQuery with respect to promoting untyped atomic values is notaligned with the July 2004 draft of the XQuery specification The untyped atomic type is promoted to the type of the otheroperand instead of xsstring as specified in the XQuery specification This is to maintain consistency across general andvalue comparison operators which we consider more important than making the value comparison transitive
Example Selecting all education elements where the GPA is greater than 35
The following query selects all Education nodes where the GPA is greater than 35 for the candidate whoseJobCandidateID is 2
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal($EDRESEduGPA) gt 35return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Node comparison operators
You can use the node comparison operator is to compare two nodes to determine if they represent the same node or notThe node comparison operator accepts two operands that are of type node
Example Comparing two address nodes to check their identity
The following query compares two address nodes to check if they represent the same node in the document
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] is (RESAddress)[1] )then
ltResultgtNodes are equalltResultgtelse
ltResultgtNodes are not equalltResultgt) as ResultFROM [HumanResources][JobCandidate]
Copy Code
Copy Code
Copy Code
WHERE JobCandidateID = 3
Node order comparison operators
You can use the node order comparison operators to ascertain the order of two nodes in a document The node ordercomparison operators supported by SQL Sever 2005 are gtgt and ltlt and both the operators accept two operands The gtgtoperator returns true if the left operand precedes the right operand in document order and the ltlt operator returns trueif the left operand follows the right operand in document order
Example Comparing the order of two address nodes
The following query compares the order of two address nodes for a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddressRESAddrType[=Home])[1] ltlt
(RESResumeRESAddressRESAddrType[=Permanent])[1] )then
ltResultgtHome address precedes Permanent addressltResultgtelse
ltResultgtHome address follows Permanent addressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Logical Operators
The logical operators supported by XQuery in SQL Server 2005 are and and or The value of any logical expressionformed using these operators can be either true or false
Example Using the and operator to create a logical expression
The following query returns the candidates education element that contains bachelor level business degree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[RESEduLevel=Bachelor and RESEduMajor=Business]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
The if-then-else Construct
Like other functional languages XQuery supports the if-then-else construct You can use the if-then-else statement toperform operations based on the value of a conditional expression
Example Using a conditional expression
The following query displays the type of address that is specified in the resume for a candidate whose JobCandidateID is3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddressreturn
if ( $ARESAddrType eq Home )then
ltResultgtHome AddressltResultgtelse
ltResultgtOther AddressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Copy Code
Copy Code
Copy Code
Constructing XML Using XQuery
XQuery constructors enable you to create XML structures within a query Constructors are available for elementsattributes processing instructions text nodes and comments
The following examples illustrate these approaches to constructing XML
Example Using constant expressions
The following query displays employment history details constructed using constant expressions
SELECT Resumequery(ltEmployer IndustryCategory=ITServicesgtltOrganizationgtABC TechnologiesltOrganizationgtltJobTitlegtSoftware EngineerltJobTitlegtltStartDategt2001-10-01ltStartDategtltEndDategt2003-05-09ltEndDategt
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]
WHERE JobCandidateID = 3
Example Using data obtained dynamically
The following query displays employment history details constructed using the results obtained from a query for acandidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmployer Organization = $EMPRESEmpOrgName gt $EMPRESEmpStartDate $EMPRESEmpEndDate $EMPRESEmpJobTitle
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using constant names for computed element and attribute constructors
The following query displays the employment history of a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
element Employerattribute Organization $EMPRESEmpOrgName element StartDate string($EMPRESEmpStartDate) element EndDate string($EMPRESEmpEndDate) element JobTitle string($EMPRESEmpJobTitle)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Performing XQuery Construction vs Shaping Using FOR XML
Some applications have a requirement to generate XML from a rowset On the server XML can be generated using a FORXML clause or XQuery constructions or XML DML operations Recommendations on using FOR XML and XQueryconstructors for constructing XML are as follows
Copy Code
Copy Code
Copy Code
l If XML is to be aggregated from multiple columns and multiple rows then FOR XML is the only choice
l If a single XML instance is to be reshaped then it can be done using XQuery as well as FOR XML XQuery might befaster since the FOR XML approach will require multiple invocations of XML data type methods on the XML instance
l You can use multiple XML DML statements to construct an XML instance This approach is significantly slower thanXQuery construction
l Use the new TYPE directive available with the FOR XML clause in SQL Server 2005 to generate the result of a FORXML query as an instance of XML data type
Built-in XQuery Functions
Implementation of XQuery in SQL Server 2005 supports a subset of the built-in functions of XQuery 10 and XPath 20These functions include data accessor functions string manipulation functions aggregate functions context functionsnumeric functions Boolean functions node functions and sequence functions The following sections explore some ofthese functions
Data Accessors
You can use the data accessor functions to extract values of nodes as strings or typed values XQuery supports two typesof data accessor functions string() which extracts the string value of an item and data() which gets the typed value Ifthe node is not a text node an attribute node or an element node then the data() function throws a static error If thenode is a document node of an untyped XML instance then data() returns a string value of the document The data()function returns a static error if the node is a complex typed element
Example Using the string() function
See the Using constant names for computed element and attribute constructors example in the section Constructing XMLUsing XQuery in this paper for a query that generates the employment history of a candidate by using the string()function and computed element constructors
Example Using the data() function
The following query generates the employment history of a candidate by using the data() function and computed elementconstructors
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) gt 35return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
String Manipulation
XQuery supports four string manipulation functions
l concat() Helps concatenate two or more strings
l contains() Helps determine whether or not a string specified as the first operand contains another string specifiedas the second operand The length of the search string is limited to 4000 Unicode characters
l substring() Helps extract portion of a string from another string known as source string
l string-length() Helps calculate the length of a string
The current release of SQL Server 2005 supports only the Unicode codepoint collation
Example Using the concat() and substring() functions
The following query generates the employment history of a candidate by concatenating the values of start date enddate organization name and job title
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmploymentgtconcat( substring(string($EMPRESEmpStartDate)110) to
substring(string($EMPRESEmpEndDate)110) string($EMPRESEmpOrgName) string($EMPRESEmpJobTitle) )
ltEmploymentgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the contains() function
The following query demonstrates the use of the contains() function by displaying Education details for a node thatcontains the string science in the value of the element EduDegree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere contains($EDRESEduDegree Science)return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Aggregate Functions
Aggregate functions operate on a sequence of items and return the aggregate values of the sequence Aggregate functionscurrently supported in the XQuery support in SQL Server 2005 are count() min() max() avg() and sum() Thefunctions min() and max() accept only base types that support the gt operator (ie the three built-in numeric basetypes the datetime base types xsstring xsboolean and xdtuntypedAtomic) A sequence of mixed types is notsupported in these functions Furthermore xdtuntypedAtomic is treated as xsdouble
For avg() and sum() the type of the passed expression needs to be a subtype of one of the three built-in numeric basetypes or untypedAtomic (but not a mixture xdtuntypedAtomic is treated as xsdouble)
The count() function returns the number of items in a sequence
Example Using the count() function
The following query displays the count of employment education and address elements present in the documentusing the count() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeltEmploymentgtElement count is count(RESResumeRESAddress) ltEmploymentgtltEducationgtElement count is count(RESResumeRESEducation) ltEducationgtltAddressgtElement count is count(RESResumeRESAddress) ltAddressgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the min() function
The following query displays the education element for which the GPA value is minimum using the min() function
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = min(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the max() function
The following query displays the education element for which the GPA value is maximum using the max() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = max(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the avg() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using theavg() function
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt avg(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoNewYorkTempLow) ltAvgLowgt
ltNewYorkgtltBostongt
ltAvgHighgt avg(WeatherInfoBostonTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Example Using the sum() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using the
Copy Code
Copy Code
Copy Code
sum() and count() functions
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt sum(WeatherInfoNewYorkTempHigh) div count
(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt sum(WeatherInfoNewYorkTempLow) div count
(WeatherInfoNewYorkTempLow) ltAvgLowgtltNewYorkgtltBostongt
ltAvgHighgt sum(WeatherInfoBostonTempHigh) div count(WeatherInfoBostonTempHigh) ltAvgHighgt
ltAvgLowgt sum(WeatherInfoBostonTempLow) div count(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Context Functions
You can use the context functions to obtain the contextual properties of a context item SQL Server 2005 implements twocontext functionsmdashlast() and position() The last() function can be used to determine the number of items in asequence and the position() function can be used to obtain the position of a context item Both the last() and position() functions without an argument can only be used in the context of a context-dependent predicate (ie inside []) in SQLServer 2005
Example Using the last() function
The following query retrieves the last address element for a candidate using the last() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[last()]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the position() function
The following query retrieves the first two address elements for a candidate using the position() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[position()lt=2]
) as Result
Copy Code
Copy Code
Copy Code
FROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type-Related Expressions
XQuery supports various types of expressions or operators that are based on the type information These expressions canbe classified as type assertion expressions type inspection expressions and type casting expressions These expressionsare discussed briefly in the following sections
Type Assertion Expressions
as xsTYPE clause in for statement
You can use the as clause to specify the type for the binding variable used in the for statement
When a type is declared for the binding variable binding values that are not of the declared type would result in typeerror The xsTYPE clause is not a cast expression but it serves as a type assertion
Example Using as xsTYPE clause with for statement
The following query binds the address node sequence to a variable $A which is defined as type element(RESAddress)
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A as element(RESAddress) in RESResumeRESAddressreturn
$A) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Type Inspection Expressions
instance of xsTYPE operator
The instance of operator helps identify the runtime type of an item in an XML document
Example Using instance of xsTYPE operator
The following query checks to see if the type of an address node identified by an XPath expression matches element() typeor not
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] instance of element() )then
ltResultgtSelected node is an ElementltResultgtelse
ltResultgtSelected node is not an ElementltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type Casting Expressions
Implicit Type Casting
The XQuery engine performs implicit type casting for numeric types and untypedAtomic values in expressions that containarithmetic operations or function invocations This process is known as type promotion Type promotion occurs when anexpression results in a numeric type that is incompatible with the expected numeric type Type promotion is performed bycasting the resulting expression to the required type
Example Implicit type casting
The following query performs an arithmetic operation on a decimal value and a double value In the current scenario the
Copy Code
Copy Code
values in the expression are added only after promoting the xsdecimal value to xsdouble
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(
ltResultgt xsdecimal(1055) + xsdouble(15e1) ltResultgt) as Result
Explicit Type Casting
Typed value constructors
XQuery provides constructor functions for all built-in types defined in the XML Schema specification These constructorsare useful for constructing typed values and also for casting values from one type to another XQuery also makesconstructors available for types that are defined in imported schemas
Example Using a value constructor for constructing values
The following query returns all Employment nodes for which the StartDate is greater than a value constructed usingconstructor for type xsdate
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentwhere $EMPRESEmpStartDate gt xsdate(1995-01-01)return
$EMP) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using a value constructor for typecasting
The following query selects all Education nodes where the GPA is greater than or equal to 38 for the candidate whoseJobCandidateID is 2 This query uses the value constructor for xsdecimal for typecasting the value of EduGPA fromxsstring to xsdecimal
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) ge 38return
element Educationelement Level string($EDRESEduLevel)element StartDate string($EDRESEduStartDate)element EndDate string($EDRESEduEndDate)element Degree string($EDRESEduDegree)element GPA string($EDRESEduGPA)element GPAScale string($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
cast as xsTYPE Operator
XQuery in SQL Server 2005 supports the cast as TYPE operator which is useful for performing explicit type castingExplicit type casting can also be performed using the xsTYPE() constructors which are more convenient to write thanthe cast as TYPE operator
Example Using cast as xsTYPE operator
The following query generates an XML that contains typed values of selected elements from Education node set for acandidate whose JobCandidateID is 3
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level $EDRESEduLevel cast as xsstring element StartDate $EDRESEduStartDate cast as xsdate element EndDate $EDRESEduEndDate cast as xsdate element Degree $EDRESEduDegree cast as xsstring element GPA $EDRESEduGPA cast as xsdecimal element GPAScale $EDRESEduGPAScale cast as xsdecimal
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using xsTYPE() operator
The following query generates the same results as the query in the previous example using the xsTYPE() operatorinstead of the cast as xsTYPE operator
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level xsstring($EDRESEduLevel) element StartDate xsdate($EDRESEduStartDate) element EndDate xsdate($EDRESEduEndDate) element Degree xsstring($EDRESEduDegree) element GPA xsdecimal($EDRESEduGPA) element GPAScale xsdecimal($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Accessing Relational Columns and Variables
When writing queries using XQuery it is not uncommon to have the requirement for accessing relational columns andvariables from within the query SQL Server 2005 caters to this requirement by implementing two functionsmdashsqlcolumn() and sqlvariable()
The function sqlcolumn() can be used to access non-XML columns in a relational table from within a query This functionis useful for scenarios such as aggregating information from XML and non-XML type columns of one or more tables usingthe values of non-XML columns to filter the results of an XQuery and so on The functions sqlcolumn() andsqlvariable() cannot be used with datetime CLR user-defined functions or XML
Example Using sqlcolumn() function
The following query generates an XML that contains values from the CustomerID and Name columns of non-XML datatype and values of YearOpened NumberOfEmployees AnnualSales and AnnualRevenue elements from theDemographics column
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyelement CustomerInfo
element CustomerID sqlcolumn(StoreCustomerID) element Name sqlcolumn(StoreName) element YearOpened string((STStoreSurveySTYearOpened)[1]) element NumberOfEmployees string((STStoreSurveySTNumberEmployees)[1]) element AnnualSales string((STStoreSurveySTAnnualSales)[1]) element AnnualRevenue string((STStoreSurveySTAnnualRevenue)[1])
) as Result
Copy Code
Copy Code
Copy Code
FROM [Sales][Store] StoreWHERE StoreCustomerID = 4
Example Using sqlvariable() function
The following stored procedure returns home address nodes of a specified candidate by using the value of theAddrType variable in the XQuery where clause to filter the results of the query
CREATE PROCEDURE [GetCandidateAddress]JobCandidateID [int]AddrType [varchar](20)
ASBEGIN
SET NOCOUNT ON
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $A[ RESAddrType = sqlvariable(AddrType) ]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = JobCandidateID
END
Example Using sqlvariable() function in conjunction with the exist() method of the XML data type
The following query returns resumes of candidates who hold a Bachelors degree with a major in Business
DECLARE EducationLevel varchar(20)SET EducationLevel = Bachelor
DECLARE Major varchar(20)SET Major = Business
SELECT JobCandidateID ResumeFROM [HumanResources][JobCandidate]WHERE Resumeexist (
declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[ RESEduLevel = sqlvariable(EducationLevel) and RESEduMajor
= sqlvariable(Major) ]) = 1
Non-Supported Features and Workarounds
Current implementation of XQuery in SQL Server 2005 does not support the following features
l The let clause The let clause which is a part of the FLWOR expression is useful for binding a variable to the resultsof an expression WorkaroundmdashInstead of using the let clause use an inline expression
l Range expression (to operator) A range expression can be used to construct a sequence of consecutive integersusing the to operator For example using a range expression such as (6 to 10) it is possible to construct thesequence (6 7 8 9 10) WorkaroundmdashInstead of using the to operator list all items in your sequence
l Type information Some features that are based on type system such as typeswitch treat as castable andvalidate expressions are currently not supported
l The functionality of a typeswitch expression is similar to the switch-case construct available in otherprogramming languages In a switch-case statement the branchescases are selected based on the value of theargument passed to the switch In a typeswitch expression the branches are selected based on the type of theargument passed to typeswitch Workaroundmdashuse if then else and instance of
l The treat as expression can be used to change the static type of the result of an expression to a specific statictype and raises a static type error if the static type of the expression does not match the specified type It doesnot change the dynamic type or value of the expression Workaroundmdashnone
l The castable expression is useful for checking whether an atomic value can be cast to the specified typeWorkaroundmdashInstead of using the expression $x castable as T use the expression empty(data($x)) or not(empty(T($x)))
Copy Code
Copy Code
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
Both the increasing need to deal with more heterogeneously structured data and the necessity of having an implied orderare two of the most important reasons why the relational data model is being extended to store XML documents nativelyIn addition the limitations of the SQL language in handling semi-structured or markup information resulted in thedevelopment of the XQuery language The XQuery language has been designed from scratch taking into consideration thenature of XML data and the issues involved in processing it
SQL Server 2005 has built-in support for the native storage of XML data using the XML data type XQuery 10 is alanguage that is being defined by the World Wide Web Consortium (W3C) XML Query Working Group to formulate queriesover XML data XQuery like SQL is a declarative query language that as we will see later can be easily understood witha basic knowledge of SQL and XPath
This paper is based on the implementation of XQuery 10 in SQL Server 2005 which in turn is based on the XQuery 10July 2004 working draft The first section of this paper provides an overview of the new XML data type and its associatedfeatures Subsequent sections introduce the new XQuery language and its advantages the FLWOR statement variousoperators in XQuery built-in functions in XQuery type-related expressions and non-supported features in SQL Server2005 respectively Finally the last sections provide information on best practices and guidelines XML data modificationand XQuery usage scenarios
The XML Data Type in SQL Server 2005
The new XML data type introduced in SQL Server 2005 provides users with the ability to store XML documents andfragments in the database An XML data type can be used to create a column a parameter to a stored procedure orfunction or a variable
Additionally the user can associate a column of type XML with an XML schema collection to create a typed XML columnThe XML schemas in the collection are used to validate and type the XML instances
Typed vs Untyped XML Data Type
An XML data type can be associated with an XML schema collection to have schema constraints enforced on XMLinstances If the XML data is associated with an XML schema collection it is called typed XML Otherwise it is calleduntyped XML
The SQL Server 2005 XML data type implements the ISO SQL-2003 standard XML data type It can store not only well-formed XML 10 documents but also so-called XML content fragments with top-level text nodes and an arbitrary numberof top-level elements Checks for well-formedness of the data are performed and these checks do not require the XMLdata type to be bound to XML schemas Data that is not well-formed (subject to the SQL-2003 content relaxations) isrejected
Untyped XML is useful when the schema is not known a priori It is also useful when the schema is known but changingrapidly and thus hard to maintain or multiple schemas exist and are late bound to the data based on externalrequirements Furthermore untyped XML is useful when the XML schemas contain XML Schema constructs not supportedby the database engine (eg keykeyref lax validation) In that case you could use the SystemXML validator inside aCLR (common language runtime) user-defined function to provide validation
If you have XML schemas in an XML schema collection describing your XML data you can associate the XML schemacollection with the XML column to yield typed XML The XML schemas are used to validate the data perform more precisetype checks than untyped XML during compilation of query and data modification statements and optimize storage andquery processing
representingsemi-structured datawith variable orevolvingschema
Markup data Not suitable for storing markup data beyondBLOB storage
Excellent forstoring markupdata such asHTML RTF andso on
Nested or hierarchical data structures Supports nested data by using multiple tablesand linking them with foreign keys but thecomplexity of queries required for searchingnested data stored in relational form increaseswhen the depth of nesting increases or isunknown
Providesexcellentsupport forexpressingnested andhierarchicaldata
Order of data Not preserved Preserved
Input data Homogeneous Heterogeneous
Result set Homogeneous Heterogeneous
Typed-XML columns parameters and variables can store XML documents or content fragments which you can specify asan option (DOCUMENT or CONTENT respectively with CONTENT as the default) at the time of declaration Furthermoreyou have to provide the collection of XML schemas Specify DOCUMENT if each XML instance has exactly one top-levelelement otherwise use CONTENT The XQuery compiler uses the DOCUMENT flag information to infer Singleton top-levelelements during static type inference
Methods of the XML Data Type
The XML data type supports five methods that can be used to manipulate XML instances The methods of the XML datatype can be described as follows
The query() method takes an XQuery expression that evaluates to a list of XML nodes and allows the user to extractfragments of an XML document The result of this method is an instance of untyped XML
The value() method is useful for extracting scalar values from XML documents as a relational value This method takes anXQuery expression that identifies a single node and the desired SQL type to be returned The value of the XML node isreturned cast to the specified SQL type
The exist() method allows the user to perform checks on XML documents to determine if the result of an XQueryexpression is empty or nonempty The result of this method is 1 if the XQuery expression returns a nonempty result 0 ifthe result is empty and NULL if the XML instance itself is NULL
Decomposing an XML document into relational data is facilitated by the nodes() method of the XML data type The nodes() method accepts an XQuery expression and returns a rowset in which each row represents a context node identified bythe query expression Methods of the XML data type such as query() value() exist() and nodes() can also beinvoked on the context nodes returned from the nodes() method
The modify() method can be used to modify the content of an XML document It accepts XML DML statements to insertupdate or delete one or more nodes from an XML instance It raises an error if applied to a NULL value
For more information see the XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ] white paper
Introduction to XQuery
XQuery is a new language for querying XML data that allows navigational access based on XPath 20 This section providesan overview of various aspects of the XQuery language such as the relationship between XQuery and XPath advantages ofusing XQuery application areas of XQuery the role of XML Schema in XQuery and so on
Overview of XPath 20
XPath 10 [ httpwwww3orgTRxpath ] as defined by the W3C is a language for locating parts of an XML documentXPath uses path-based syntax for identifying nodes in the XML document It also defines the core syntax for both XSLT 10[ httpwwww3orgTRxslt ] and XPointer [ httpwwww3orgTRWD-xptr ] XPath 10 has built-in functions tohandle strings Boolean values and floating point numbers It defines the syntax for filtering the node set with the abilityto specify filtering criteria XPath 10 is being extended in XPath 20 [ httpwwww3orgTRxpath20 ] to support amore detailed type system and to provide more functionality XQuery 10 [ httpwwww3orgTRxquery ] in turn isbased on XPath 20 and adds ordering reshaping construction and validation capabilities to the navigational and filteringaspects of XPath 20
Overview of XQuery
XQuery is a declarative typed functional language designed from scratch by the XML Query Working Group specifically forthe purpose of querying data stored in XML format XQuery shares the same data model and the same XML Schema[ httpwwww3orgXMLSchema ] -based type system with other members of the XML standards family such as XPath20 and XSLT 20 [ httpwwww3orgTRxslt20 ] XQuery is designed to work with XML documents that are untyped(no schema associated with the data) typed with XML schemas or a combination of both As previously mentionedXQuery 10 is basically a superset of XPath 20 In addition to the features of XPath 20 it has the following capabilities
l Adds an order by clause to the FLWOR clause to sort in non-document order
l Adds a let clause to the FLWOR clause to name results of expressions for further use (not supported in SQL Server2005)
l Provides a way to specify static context items in the query prolog (such as namespace prefix bindings)
l Provides the ability to construct new nodes
l Provides the ability to define user-defined functions (not supported in SQL Server 2005)
l Provides the ability to create moduleslibraries (not supported in SQL Server 2005)
Advantages of XQuery
l It is easy to learn if knowledge of SQL and XPath is present
l When queries are written in XQuery they require less code as compared to queries written in XSLT
l XQuery can be used as a strongly typed language when the XML data is typed which can improve the performanceof the query by avoiding implicit type casts and provide type assurances that can be used when performing queryoptimization
l XQuery can be used as a weakly typed language for untyped data to provide high usability SQL Server 2005implements static type inferencing with support for both strong and weak type relationships
l Because XQuery requires less code to perform a query than does XSLT maintenance costs are lower
l XQuery is going to be a W3C recommendation and will be supported by major database vendors
Caveat regarding XQuery 10 language as of the writing of this document
l The XQuery specification is currently under development and may change in the future SQL Server 2005 implementsa stable part of the W3C working draft
Application Areas of XQuery
Application areas of XQuery can be classified broadly as follows
l XQuery for queryanalysis XQuery is excellent for querying huge chunks of data and provides the capability tofilter sort order and repurpose the required information Typical applications include querying XML documents thatrepresent semi-structured information name-value pair property bags analysis of application logs transaction logsand audit logs to identify potential application errors and security issues and so on
l XQuery for application integration As organizations move away from proprietary application integrationapproaches and start adopting standards based application integration approaches the need for transforming datafrom internal application-specific formats to standard exchange formats is gaining more focus Because of its abilityto construct and transform XML data XQuery caters to this need One typical use of XQuery in the application-integration domain is translating the vocabulary used by one application that uses native XML databaserelationaldata source into a language used by another application that uses XMLrelational data format
Advantages of Using XQuery at the Server
Performing XML processing at the server using XQuery has many advantages compared to client-side XML processingSome of these advantages can be summarized as follows
l Reduced traffic on the network When XML data is processed on the server only the results are forwarded to theclient This results in reduced traffic on the network
l More security Only the data that is required is sent to the client thereby avoiding the risk of exposing the entiredata to the network as is the case when using client-side XML processing
l Better maintainability Processing XML on the server results in browser independent code on the client whichleads to better maintainability on the client side
l Improved performance Queries written using XQuery on the server are subjected to optimization by the SQLquery engine This results in improved performance when compared to retrieving the entire data and filtering thedata at the client Furthermore indexes can be created on the XML data type column to achieve enhancedperformance
How XQuery Implementation Uses XML Schemas
The XML schema collection associated with an XML data type is used by the relational engine as follows
l To validate the XML instances during insertion operations
l To validate the XML instances during modification operations
l Type information contained in the XML schema is used during static type checking for early error detection and forquery performance improvements by generating better query plans and avoiding many runtime inspections
l Type information present in the XML schema is used by the SQL Server to optimize storage
Structure of the XQuery Expression
An XQuery expression in SQL Server 2005 consists of two sectionsmdasha prolog and a body A prolog can in turn contain anamespace declaration subsection Namespace declarations are used to define a mapping between prefix and namespaceURI thereby enabling you to use the prefix instead of the namespace URI in the query body You can also refer to elementnames without the prefix by binding a default namespace for element names using the declare default namespacedeclaration
The body of an XQuery expression contains query expressions that define the result of the query It can for example bethe signature FLWOR expression (see The FLWOR Statement in this paper) an XPath 20 expression (see XPath 20
Expressions in this paper) or another XQuery expression such as a construction or arithmetic expression
Example Specifying default namespace in prolog section of XQuery
The following query selects all Employment nodes for a candidate whose JobCandidateID is 3 The query defines adefault namespace and does not use a namespace prefix
SELECT Resumequery(declare default namespace httpschemasmicrosoftcomsqlserver200407adventure-
worksResumeResumeEmployment
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Specifying namespace using the WITH XMLNAMESPACES clause
SQL Server also supports the SQL-2003 standard extension that allows a user to declare XML namespace bindings in theSQL WITH clause on a per SQL query basis thus avoiding repetitive declarations in multiple XML data type methodinvocations The following query shows the modified version of the query shown in the previous example This querydeclares a namespace using the WITH XMLNAMESPACES clause
WITH XMLNAMESPACES( httpschemasmicrosoftcomsqlserver200407adventure-worksResumeAS RES)SELECT Resumequery(
RESResumeRESEmployment) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
XPath 20 Expressions
XQuery uses XPath 20 expressions to locate nodes in a document and to navigate from one location to another within asingle document or across documents Navigation paths defined using XPath consist of a sequence of steps separated by A single step comprises an axis a node test and zero or more step qualifiers
The axis specifies the direction of movement relative to the context node Supported axes in SQL Server 2005 are childdescendant parent attribute self and descendant-or-self
A node test specifies a condition that all the nodes that are selected by a step must satisfy The node condition can bespecified based on node name or node type
Step qualifiers can be defined by using predicates or dereferences A predicate is an expression that acts as a filter on anode sequence and is specified within square brackets A dereference maps the elements andor attributes nodes in anode sequence to the nodes that they reference A node sequence passed as an input to the dereference must containelements or attributes of type IDREF or IDREFS The dereference generates a new sequence consisting of the elementnodes whose ID-type attribute values match the IDREF values extracted from the elements and attributes in the inputsequence
The steps of an XPath expression are evaluated from left to right Execution of a step sets the evaluation context items forthe next step A context item in a path expression is a node that is selected as a result of the execution of a step in anXPath expression A step is evaluated relative to the context item that was obtained in the previous step The result of anXPath expression is a sequence of nodes in document order that are obtained after executing all the steps in theexpression in the order from left to right in the path expression
This example expression uses the column Resume which is of type XML in table [HumanResources][JobCandidate] fromthe AdventureWorks database for the purpose of illustrating the concept of path expressions The following pathexpression selects all address nodes for which the address type is set to Home
childnsAddrType[=Home]parentnode()
In the preceding path expression
l child is the axis specifier
l is the axis separator
Copy Code
Copy Code
Copy Code
l ns is the namespace prefix
l AddrType is the node test
l [=Home] is the predicate expression where refers to the context node
XQuery also supports abbreviated syntax for specifying the axis The following table shows the axis and correspondingabbreviated syntax
Table 2 Abbreviated syntax for axes
Example Selecting organization names from employment history
The following XPath expression selects the children text nodes of EmpOrgName elements that are child nodes of nodeResumeEmployment Here text() is used to select the text node of the EmpOrgName element
ResumeEmploymentEmpOrgNametext()
The FLWOR Statement
FLWOR statements form the core expressions of XQuery and are similar to the SELECT statements of SQL The acronymFLWOR (pronounced flower) stands for FOR LET WHERE ORDER BY RETURN FLWOR expressions in XQuery enableusers to specify operations such as declarative iteration variable binding filtering sorting and returning the results SQLServer 2005 supports FOR WHERE ORDER BY and RETURN
For
The for clause in a FLWOR expression enables users to define a declarative iteration of a bound variable over an inputsequence The input sequence can be specified using XPath expressions sequence of atomic values a sequenceconstructed using literals or constructor functions It is therefore analogous to the SQL SELECT FROM clause and is notlike a programming language for construct
Variable binding is also specified in the for clause
Example Selecting all home address elements from resume using the for clause
The following query selects all Address nodes where the type of address is set to Home and the JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddressRESAddrType[=Home]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
where
The where clause filters the results of an iteration by applying the expression specified with the where clause
Example Selecting all home address elements using the where clause
The following query selects all Address nodes where the type of address is set to Home and the JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $ARESAddrType[=Home]
Axis Abbreviated form
Attribute
Child
descendant-or-selfnode()
parentnode()
selfnode()
Copy Code
Copy Code
return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
order by
The order by keyword enables you to sort the values in the returned result set The order by keyword accepts a sortingexpression which should return an atomic value Optionally you can also specify ascending or descending for the sortorder The default sort order is ascending
Example Selecting employment history in ascending order using the order by clause
The following query selects all Employment nodes in ascending order of employment starting date for a candidate whoseJobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentorder by $EMPRESEmpStartDatereturn$EMP
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
return
The return clause which is analogous to the SELECT clause in SQL enables users to define the result of a query You canspecify any valid XQuery expression in the return clause You can also construct XML structures in the return section byspecifying constructors for elements attributes etc
Example Selecting specific elements of employment history using the return clause
The following query selects StartDate EndDate OrgName JobTitle elements of Employment node for a candidate whoseJobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentorder by $EMPRESEmpStartDatereturn
ltEmploymentgt $EMPRESEmpStartDate $EMPRESEmpEndDate $EMPRESEmpOrgName $EMPRESEmpJobTitle
ltEmploymentgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Current implementation of XQuery in SQL Server 2005 does not support the let clause This aspect is discussed further inNon-supported Features and Workarounds in this paper
FLWOR Expressions vs XPath Expressions
Using a FLWOR expression to define the result sequence when the sequence can be expressed using an XPath expressionincurs a performance penalty because the query plan contains a JOIN operation between the for variable and the body ofthe for clause The use of a FLWOR expression is justified only if one or more of the following conditions are satisfied
l If you want to iterate over a sequence of values that are returned as a result of an expression This is achieved usingthe for clause which binds a variable to successive values of the result set Examples are the construction of newelements within the scope of the for clause and the retention of duplicates
l When you want to filter the result sequence of the for clause based on a predicate which cannot be defined using
Copy Code
Copy Code
simple XPath expressions The where clause is used to eliminate unwanted values in the result set An example is asfollows
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(for $i in (1 2 3) $j in (3 4 5)where $i lt $jreturn sum($i + $j)) as Result
l If you want to sort the result set based on a sorting expression Sorting is defined on the result set using the orderby clause
l When you want to define the shape of the returned result set using the results obtained from the for clause Thereturn statement is used to perform the shaping of the result set
In all other cases using XPath expressions is recommended
Operators in XQuery
As a functional language XQuery in SQL Server 2005 supports various types of functions and operators that can begrouped under the following categories
l Arithmetic operators
l Comparison operators
l Logical operators
Table 3 Operators supported in SQL Server 2005
Arithmetic Operators
SQL Server 2005 supports five arithmetic operators These are + b div and mod Currently it does not support idiv
Example Converting selected values of store survey information
This example is based on the [Sales][Store] table in the AdventureWorks database The following query returns values ofAnnualSales AnnualRevenue in yen and the store area in square meters for a store whose CustomerID is 3
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyfor $S in STStoreSurveyreturn
ltStoreDetailsSalesInYen = $SSTAnnualSales1068100 RevenueInYen = $SSTAnnualRevenue1068100 StoreAreaInSqMeters = $SSTSquareFeet00929 gt
ltStoreDetailsgt) as ResultFROM [Sales][Store]WHERE CustomerID = 3
Comparison Operators
Copy Code
Type Operators
Arithmetic operators +-div mod
General comparison operators = = lt gt lt= gt=
Value comparison operators eq ne lt gt le ge
Node comparison operator is
Node order comparison operators gtgt ltlt
Logical operators and or
Copy Code
SQL Server 2005 has implemented support for four types of comparison operatorsmdashgeneral comparison operators valuecomparison operators node comparison operators and node order comparison operators
General comparison operators
General comparison operators help compare atomic values sequences or a combination of the two General comparisonoperators are = = lt gt lt= and gt= A general comparison is existentially quantified meaning that any match willresult in true
Example Selecting all address elements where the address type is not set to Home
The following query selects all Address nodes where the type of address is not set to Home and the JobCandidateID is3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $ARESAddrType[=Home]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Value comparison operators
Value comparison operators help compare atomic values Value comparison operators supported by SQL Server 2005 areeq ne lt gt le and ge The current implementation of XQuery with respect to promoting untyped atomic values is notaligned with the July 2004 draft of the XQuery specification The untyped atomic type is promoted to the type of the otheroperand instead of xsstring as specified in the XQuery specification This is to maintain consistency across general andvalue comparison operators which we consider more important than making the value comparison transitive
Example Selecting all education elements where the GPA is greater than 35
The following query selects all Education nodes where the GPA is greater than 35 for the candidate whoseJobCandidateID is 2
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal($EDRESEduGPA) gt 35return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Node comparison operators
You can use the node comparison operator is to compare two nodes to determine if they represent the same node or notThe node comparison operator accepts two operands that are of type node
Example Comparing two address nodes to check their identity
The following query compares two address nodes to check if they represent the same node in the document
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] is (RESAddress)[1] )then
ltResultgtNodes are equalltResultgtelse
ltResultgtNodes are not equalltResultgt) as ResultFROM [HumanResources][JobCandidate]
Copy Code
Copy Code
Copy Code
WHERE JobCandidateID = 3
Node order comparison operators
You can use the node order comparison operators to ascertain the order of two nodes in a document The node ordercomparison operators supported by SQL Sever 2005 are gtgt and ltlt and both the operators accept two operands The gtgtoperator returns true if the left operand precedes the right operand in document order and the ltlt operator returns trueif the left operand follows the right operand in document order
Example Comparing the order of two address nodes
The following query compares the order of two address nodes for a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddressRESAddrType[=Home])[1] ltlt
(RESResumeRESAddressRESAddrType[=Permanent])[1] )then
ltResultgtHome address precedes Permanent addressltResultgtelse
ltResultgtHome address follows Permanent addressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Logical Operators
The logical operators supported by XQuery in SQL Server 2005 are and and or The value of any logical expressionformed using these operators can be either true or false
Example Using the and operator to create a logical expression
The following query returns the candidates education element that contains bachelor level business degree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[RESEduLevel=Bachelor and RESEduMajor=Business]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
The if-then-else Construct
Like other functional languages XQuery supports the if-then-else construct You can use the if-then-else statement toperform operations based on the value of a conditional expression
Example Using a conditional expression
The following query displays the type of address that is specified in the resume for a candidate whose JobCandidateID is3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddressreturn
if ( $ARESAddrType eq Home )then
ltResultgtHome AddressltResultgtelse
ltResultgtOther AddressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Copy Code
Copy Code
Copy Code
Constructing XML Using XQuery
XQuery constructors enable you to create XML structures within a query Constructors are available for elementsattributes processing instructions text nodes and comments
The following examples illustrate these approaches to constructing XML
Example Using constant expressions
The following query displays employment history details constructed using constant expressions
SELECT Resumequery(ltEmployer IndustryCategory=ITServicesgtltOrganizationgtABC TechnologiesltOrganizationgtltJobTitlegtSoftware EngineerltJobTitlegtltStartDategt2001-10-01ltStartDategtltEndDategt2003-05-09ltEndDategt
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]
WHERE JobCandidateID = 3
Example Using data obtained dynamically
The following query displays employment history details constructed using the results obtained from a query for acandidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmployer Organization = $EMPRESEmpOrgName gt $EMPRESEmpStartDate $EMPRESEmpEndDate $EMPRESEmpJobTitle
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using constant names for computed element and attribute constructors
The following query displays the employment history of a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
element Employerattribute Organization $EMPRESEmpOrgName element StartDate string($EMPRESEmpStartDate) element EndDate string($EMPRESEmpEndDate) element JobTitle string($EMPRESEmpJobTitle)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Performing XQuery Construction vs Shaping Using FOR XML
Some applications have a requirement to generate XML from a rowset On the server XML can be generated using a FORXML clause or XQuery constructions or XML DML operations Recommendations on using FOR XML and XQueryconstructors for constructing XML are as follows
Copy Code
Copy Code
Copy Code
l If XML is to be aggregated from multiple columns and multiple rows then FOR XML is the only choice
l If a single XML instance is to be reshaped then it can be done using XQuery as well as FOR XML XQuery might befaster since the FOR XML approach will require multiple invocations of XML data type methods on the XML instance
l You can use multiple XML DML statements to construct an XML instance This approach is significantly slower thanXQuery construction
l Use the new TYPE directive available with the FOR XML clause in SQL Server 2005 to generate the result of a FORXML query as an instance of XML data type
Built-in XQuery Functions
Implementation of XQuery in SQL Server 2005 supports a subset of the built-in functions of XQuery 10 and XPath 20These functions include data accessor functions string manipulation functions aggregate functions context functionsnumeric functions Boolean functions node functions and sequence functions The following sections explore some ofthese functions
Data Accessors
You can use the data accessor functions to extract values of nodes as strings or typed values XQuery supports two typesof data accessor functions string() which extracts the string value of an item and data() which gets the typed value Ifthe node is not a text node an attribute node or an element node then the data() function throws a static error If thenode is a document node of an untyped XML instance then data() returns a string value of the document The data()function returns a static error if the node is a complex typed element
Example Using the string() function
See the Using constant names for computed element and attribute constructors example in the section Constructing XMLUsing XQuery in this paper for a query that generates the employment history of a candidate by using the string()function and computed element constructors
Example Using the data() function
The following query generates the employment history of a candidate by using the data() function and computed elementconstructors
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) gt 35return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
String Manipulation
XQuery supports four string manipulation functions
l concat() Helps concatenate two or more strings
l contains() Helps determine whether or not a string specified as the first operand contains another string specifiedas the second operand The length of the search string is limited to 4000 Unicode characters
l substring() Helps extract portion of a string from another string known as source string
l string-length() Helps calculate the length of a string
The current release of SQL Server 2005 supports only the Unicode codepoint collation
Example Using the concat() and substring() functions
The following query generates the employment history of a candidate by concatenating the values of start date enddate organization name and job title
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmploymentgtconcat( substring(string($EMPRESEmpStartDate)110) to
substring(string($EMPRESEmpEndDate)110) string($EMPRESEmpOrgName) string($EMPRESEmpJobTitle) )
ltEmploymentgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the contains() function
The following query demonstrates the use of the contains() function by displaying Education details for a node thatcontains the string science in the value of the element EduDegree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere contains($EDRESEduDegree Science)return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Aggregate Functions
Aggregate functions operate on a sequence of items and return the aggregate values of the sequence Aggregate functionscurrently supported in the XQuery support in SQL Server 2005 are count() min() max() avg() and sum() Thefunctions min() and max() accept only base types that support the gt operator (ie the three built-in numeric basetypes the datetime base types xsstring xsboolean and xdtuntypedAtomic) A sequence of mixed types is notsupported in these functions Furthermore xdtuntypedAtomic is treated as xsdouble
For avg() and sum() the type of the passed expression needs to be a subtype of one of the three built-in numeric basetypes or untypedAtomic (but not a mixture xdtuntypedAtomic is treated as xsdouble)
The count() function returns the number of items in a sequence
Example Using the count() function
The following query displays the count of employment education and address elements present in the documentusing the count() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeltEmploymentgtElement count is count(RESResumeRESAddress) ltEmploymentgtltEducationgtElement count is count(RESResumeRESEducation) ltEducationgtltAddressgtElement count is count(RESResumeRESAddress) ltAddressgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the min() function
The following query displays the education element for which the GPA value is minimum using the min() function
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = min(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the max() function
The following query displays the education element for which the GPA value is maximum using the max() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = max(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the avg() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using theavg() function
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt avg(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoNewYorkTempLow) ltAvgLowgt
ltNewYorkgtltBostongt
ltAvgHighgt avg(WeatherInfoBostonTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Example Using the sum() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using the
Copy Code
Copy Code
Copy Code
sum() and count() functions
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt sum(WeatherInfoNewYorkTempHigh) div count
(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt sum(WeatherInfoNewYorkTempLow) div count
(WeatherInfoNewYorkTempLow) ltAvgLowgtltNewYorkgtltBostongt
ltAvgHighgt sum(WeatherInfoBostonTempHigh) div count(WeatherInfoBostonTempHigh) ltAvgHighgt
ltAvgLowgt sum(WeatherInfoBostonTempLow) div count(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Context Functions
You can use the context functions to obtain the contextual properties of a context item SQL Server 2005 implements twocontext functionsmdashlast() and position() The last() function can be used to determine the number of items in asequence and the position() function can be used to obtain the position of a context item Both the last() and position() functions without an argument can only be used in the context of a context-dependent predicate (ie inside []) in SQLServer 2005
Example Using the last() function
The following query retrieves the last address element for a candidate using the last() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[last()]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the position() function
The following query retrieves the first two address elements for a candidate using the position() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[position()lt=2]
) as Result
Copy Code
Copy Code
Copy Code
FROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type-Related Expressions
XQuery supports various types of expressions or operators that are based on the type information These expressions canbe classified as type assertion expressions type inspection expressions and type casting expressions These expressionsare discussed briefly in the following sections
Type Assertion Expressions
as xsTYPE clause in for statement
You can use the as clause to specify the type for the binding variable used in the for statement
When a type is declared for the binding variable binding values that are not of the declared type would result in typeerror The xsTYPE clause is not a cast expression but it serves as a type assertion
Example Using as xsTYPE clause with for statement
The following query binds the address node sequence to a variable $A which is defined as type element(RESAddress)
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A as element(RESAddress) in RESResumeRESAddressreturn
$A) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Type Inspection Expressions
instance of xsTYPE operator
The instance of operator helps identify the runtime type of an item in an XML document
Example Using instance of xsTYPE operator
The following query checks to see if the type of an address node identified by an XPath expression matches element() typeor not
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] instance of element() )then
ltResultgtSelected node is an ElementltResultgtelse
ltResultgtSelected node is not an ElementltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type Casting Expressions
Implicit Type Casting
The XQuery engine performs implicit type casting for numeric types and untypedAtomic values in expressions that containarithmetic operations or function invocations This process is known as type promotion Type promotion occurs when anexpression results in a numeric type that is incompatible with the expected numeric type Type promotion is performed bycasting the resulting expression to the required type
Example Implicit type casting
The following query performs an arithmetic operation on a decimal value and a double value In the current scenario the
Copy Code
Copy Code
values in the expression are added only after promoting the xsdecimal value to xsdouble
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(
ltResultgt xsdecimal(1055) + xsdouble(15e1) ltResultgt) as Result
Explicit Type Casting
Typed value constructors
XQuery provides constructor functions for all built-in types defined in the XML Schema specification These constructorsare useful for constructing typed values and also for casting values from one type to another XQuery also makesconstructors available for types that are defined in imported schemas
Example Using a value constructor for constructing values
The following query returns all Employment nodes for which the StartDate is greater than a value constructed usingconstructor for type xsdate
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentwhere $EMPRESEmpStartDate gt xsdate(1995-01-01)return
$EMP) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using a value constructor for typecasting
The following query selects all Education nodes where the GPA is greater than or equal to 38 for the candidate whoseJobCandidateID is 2 This query uses the value constructor for xsdecimal for typecasting the value of EduGPA fromxsstring to xsdecimal
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) ge 38return
element Educationelement Level string($EDRESEduLevel)element StartDate string($EDRESEduStartDate)element EndDate string($EDRESEduEndDate)element Degree string($EDRESEduDegree)element GPA string($EDRESEduGPA)element GPAScale string($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
cast as xsTYPE Operator
XQuery in SQL Server 2005 supports the cast as TYPE operator which is useful for performing explicit type castingExplicit type casting can also be performed using the xsTYPE() constructors which are more convenient to write thanthe cast as TYPE operator
Example Using cast as xsTYPE operator
The following query generates an XML that contains typed values of selected elements from Education node set for acandidate whose JobCandidateID is 3
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level $EDRESEduLevel cast as xsstring element StartDate $EDRESEduStartDate cast as xsdate element EndDate $EDRESEduEndDate cast as xsdate element Degree $EDRESEduDegree cast as xsstring element GPA $EDRESEduGPA cast as xsdecimal element GPAScale $EDRESEduGPAScale cast as xsdecimal
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using xsTYPE() operator
The following query generates the same results as the query in the previous example using the xsTYPE() operatorinstead of the cast as xsTYPE operator
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level xsstring($EDRESEduLevel) element StartDate xsdate($EDRESEduStartDate) element EndDate xsdate($EDRESEduEndDate) element Degree xsstring($EDRESEduDegree) element GPA xsdecimal($EDRESEduGPA) element GPAScale xsdecimal($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Accessing Relational Columns and Variables
When writing queries using XQuery it is not uncommon to have the requirement for accessing relational columns andvariables from within the query SQL Server 2005 caters to this requirement by implementing two functionsmdashsqlcolumn() and sqlvariable()
The function sqlcolumn() can be used to access non-XML columns in a relational table from within a query This functionis useful for scenarios such as aggregating information from XML and non-XML type columns of one or more tables usingthe values of non-XML columns to filter the results of an XQuery and so on The functions sqlcolumn() andsqlvariable() cannot be used with datetime CLR user-defined functions or XML
Example Using sqlcolumn() function
The following query generates an XML that contains values from the CustomerID and Name columns of non-XML datatype and values of YearOpened NumberOfEmployees AnnualSales and AnnualRevenue elements from theDemographics column
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyelement CustomerInfo
element CustomerID sqlcolumn(StoreCustomerID) element Name sqlcolumn(StoreName) element YearOpened string((STStoreSurveySTYearOpened)[1]) element NumberOfEmployees string((STStoreSurveySTNumberEmployees)[1]) element AnnualSales string((STStoreSurveySTAnnualSales)[1]) element AnnualRevenue string((STStoreSurveySTAnnualRevenue)[1])
) as Result
Copy Code
Copy Code
Copy Code
FROM [Sales][Store] StoreWHERE StoreCustomerID = 4
Example Using sqlvariable() function
The following stored procedure returns home address nodes of a specified candidate by using the value of theAddrType variable in the XQuery where clause to filter the results of the query
CREATE PROCEDURE [GetCandidateAddress]JobCandidateID [int]AddrType [varchar](20)
ASBEGIN
SET NOCOUNT ON
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $A[ RESAddrType = sqlvariable(AddrType) ]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = JobCandidateID
END
Example Using sqlvariable() function in conjunction with the exist() method of the XML data type
The following query returns resumes of candidates who hold a Bachelors degree with a major in Business
DECLARE EducationLevel varchar(20)SET EducationLevel = Bachelor
DECLARE Major varchar(20)SET Major = Business
SELECT JobCandidateID ResumeFROM [HumanResources][JobCandidate]WHERE Resumeexist (
declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[ RESEduLevel = sqlvariable(EducationLevel) and RESEduMajor
= sqlvariable(Major) ]) = 1
Non-Supported Features and Workarounds
Current implementation of XQuery in SQL Server 2005 does not support the following features
l The let clause The let clause which is a part of the FLWOR expression is useful for binding a variable to the resultsof an expression WorkaroundmdashInstead of using the let clause use an inline expression
l Range expression (to operator) A range expression can be used to construct a sequence of consecutive integersusing the to operator For example using a range expression such as (6 to 10) it is possible to construct thesequence (6 7 8 9 10) WorkaroundmdashInstead of using the to operator list all items in your sequence
l Type information Some features that are based on type system such as typeswitch treat as castable andvalidate expressions are currently not supported
l The functionality of a typeswitch expression is similar to the switch-case construct available in otherprogramming languages In a switch-case statement the branchescases are selected based on the value of theargument passed to the switch In a typeswitch expression the branches are selected based on the type of theargument passed to typeswitch Workaroundmdashuse if then else and instance of
l The treat as expression can be used to change the static type of the result of an expression to a specific statictype and raises a static type error if the static type of the expression does not match the specified type It doesnot change the dynamic type or value of the expression Workaroundmdashnone
l The castable expression is useful for checking whether an atomic value can be cast to the specified typeWorkaroundmdashInstead of using the expression $x castable as T use the expression empty(data($x)) or not(empty(T($x)))
Copy Code
Copy Code
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
Typed-XML columns parameters and variables can store XML documents or content fragments which you can specify asan option (DOCUMENT or CONTENT respectively with CONTENT as the default) at the time of declaration Furthermoreyou have to provide the collection of XML schemas Specify DOCUMENT if each XML instance has exactly one top-levelelement otherwise use CONTENT The XQuery compiler uses the DOCUMENT flag information to infer Singleton top-levelelements during static type inference
Methods of the XML Data Type
The XML data type supports five methods that can be used to manipulate XML instances The methods of the XML datatype can be described as follows
The query() method takes an XQuery expression that evaluates to a list of XML nodes and allows the user to extractfragments of an XML document The result of this method is an instance of untyped XML
The value() method is useful for extracting scalar values from XML documents as a relational value This method takes anXQuery expression that identifies a single node and the desired SQL type to be returned The value of the XML node isreturned cast to the specified SQL type
The exist() method allows the user to perform checks on XML documents to determine if the result of an XQueryexpression is empty or nonempty The result of this method is 1 if the XQuery expression returns a nonempty result 0 ifthe result is empty and NULL if the XML instance itself is NULL
Decomposing an XML document into relational data is facilitated by the nodes() method of the XML data type The nodes() method accepts an XQuery expression and returns a rowset in which each row represents a context node identified bythe query expression Methods of the XML data type such as query() value() exist() and nodes() can also beinvoked on the context nodes returned from the nodes() method
The modify() method can be used to modify the content of an XML document It accepts XML DML statements to insertupdate or delete one or more nodes from an XML instance It raises an error if applied to a NULL value
For more information see the XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ] white paper
Introduction to XQuery
XQuery is a new language for querying XML data that allows navigational access based on XPath 20 This section providesan overview of various aspects of the XQuery language such as the relationship between XQuery and XPath advantages ofusing XQuery application areas of XQuery the role of XML Schema in XQuery and so on
Overview of XPath 20
XPath 10 [ httpwwww3orgTRxpath ] as defined by the W3C is a language for locating parts of an XML documentXPath uses path-based syntax for identifying nodes in the XML document It also defines the core syntax for both XSLT 10[ httpwwww3orgTRxslt ] and XPointer [ httpwwww3orgTRWD-xptr ] XPath 10 has built-in functions tohandle strings Boolean values and floating point numbers It defines the syntax for filtering the node set with the abilityto specify filtering criteria XPath 10 is being extended in XPath 20 [ httpwwww3orgTRxpath20 ] to support amore detailed type system and to provide more functionality XQuery 10 [ httpwwww3orgTRxquery ] in turn isbased on XPath 20 and adds ordering reshaping construction and validation capabilities to the navigational and filteringaspects of XPath 20
Overview of XQuery
XQuery is a declarative typed functional language designed from scratch by the XML Query Working Group specifically forthe purpose of querying data stored in XML format XQuery shares the same data model and the same XML Schema[ httpwwww3orgXMLSchema ] -based type system with other members of the XML standards family such as XPath20 and XSLT 20 [ httpwwww3orgTRxslt20 ] XQuery is designed to work with XML documents that are untyped(no schema associated with the data) typed with XML schemas or a combination of both As previously mentionedXQuery 10 is basically a superset of XPath 20 In addition to the features of XPath 20 it has the following capabilities
l Adds an order by clause to the FLWOR clause to sort in non-document order
l Adds a let clause to the FLWOR clause to name results of expressions for further use (not supported in SQL Server2005)
l Provides a way to specify static context items in the query prolog (such as namespace prefix bindings)
l Provides the ability to construct new nodes
l Provides the ability to define user-defined functions (not supported in SQL Server 2005)
l Provides the ability to create moduleslibraries (not supported in SQL Server 2005)
Advantages of XQuery
l It is easy to learn if knowledge of SQL and XPath is present
l When queries are written in XQuery they require less code as compared to queries written in XSLT
l XQuery can be used as a strongly typed language when the XML data is typed which can improve the performanceof the query by avoiding implicit type casts and provide type assurances that can be used when performing queryoptimization
l XQuery can be used as a weakly typed language for untyped data to provide high usability SQL Server 2005implements static type inferencing with support for both strong and weak type relationships
l Because XQuery requires less code to perform a query than does XSLT maintenance costs are lower
l XQuery is going to be a W3C recommendation and will be supported by major database vendors
Caveat regarding XQuery 10 language as of the writing of this document
l The XQuery specification is currently under development and may change in the future SQL Server 2005 implementsa stable part of the W3C working draft
Application Areas of XQuery
Application areas of XQuery can be classified broadly as follows
l XQuery for queryanalysis XQuery is excellent for querying huge chunks of data and provides the capability tofilter sort order and repurpose the required information Typical applications include querying XML documents thatrepresent semi-structured information name-value pair property bags analysis of application logs transaction logsand audit logs to identify potential application errors and security issues and so on
l XQuery for application integration As organizations move away from proprietary application integrationapproaches and start adopting standards based application integration approaches the need for transforming datafrom internal application-specific formats to standard exchange formats is gaining more focus Because of its abilityto construct and transform XML data XQuery caters to this need One typical use of XQuery in the application-integration domain is translating the vocabulary used by one application that uses native XML databaserelationaldata source into a language used by another application that uses XMLrelational data format
Advantages of Using XQuery at the Server
Performing XML processing at the server using XQuery has many advantages compared to client-side XML processingSome of these advantages can be summarized as follows
l Reduced traffic on the network When XML data is processed on the server only the results are forwarded to theclient This results in reduced traffic on the network
l More security Only the data that is required is sent to the client thereby avoiding the risk of exposing the entiredata to the network as is the case when using client-side XML processing
l Better maintainability Processing XML on the server results in browser independent code on the client whichleads to better maintainability on the client side
l Improved performance Queries written using XQuery on the server are subjected to optimization by the SQLquery engine This results in improved performance when compared to retrieving the entire data and filtering thedata at the client Furthermore indexes can be created on the XML data type column to achieve enhancedperformance
How XQuery Implementation Uses XML Schemas
The XML schema collection associated with an XML data type is used by the relational engine as follows
l To validate the XML instances during insertion operations
l To validate the XML instances during modification operations
l Type information contained in the XML schema is used during static type checking for early error detection and forquery performance improvements by generating better query plans and avoiding many runtime inspections
l Type information present in the XML schema is used by the SQL Server to optimize storage
Structure of the XQuery Expression
An XQuery expression in SQL Server 2005 consists of two sectionsmdasha prolog and a body A prolog can in turn contain anamespace declaration subsection Namespace declarations are used to define a mapping between prefix and namespaceURI thereby enabling you to use the prefix instead of the namespace URI in the query body You can also refer to elementnames without the prefix by binding a default namespace for element names using the declare default namespacedeclaration
The body of an XQuery expression contains query expressions that define the result of the query It can for example bethe signature FLWOR expression (see The FLWOR Statement in this paper) an XPath 20 expression (see XPath 20
Expressions in this paper) or another XQuery expression such as a construction or arithmetic expression
Example Specifying default namespace in prolog section of XQuery
The following query selects all Employment nodes for a candidate whose JobCandidateID is 3 The query defines adefault namespace and does not use a namespace prefix
SELECT Resumequery(declare default namespace httpschemasmicrosoftcomsqlserver200407adventure-
worksResumeResumeEmployment
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Specifying namespace using the WITH XMLNAMESPACES clause
SQL Server also supports the SQL-2003 standard extension that allows a user to declare XML namespace bindings in theSQL WITH clause on a per SQL query basis thus avoiding repetitive declarations in multiple XML data type methodinvocations The following query shows the modified version of the query shown in the previous example This querydeclares a namespace using the WITH XMLNAMESPACES clause
WITH XMLNAMESPACES( httpschemasmicrosoftcomsqlserver200407adventure-worksResumeAS RES)SELECT Resumequery(
RESResumeRESEmployment) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
XPath 20 Expressions
XQuery uses XPath 20 expressions to locate nodes in a document and to navigate from one location to another within asingle document or across documents Navigation paths defined using XPath consist of a sequence of steps separated by A single step comprises an axis a node test and zero or more step qualifiers
The axis specifies the direction of movement relative to the context node Supported axes in SQL Server 2005 are childdescendant parent attribute self and descendant-or-self
A node test specifies a condition that all the nodes that are selected by a step must satisfy The node condition can bespecified based on node name or node type
Step qualifiers can be defined by using predicates or dereferences A predicate is an expression that acts as a filter on anode sequence and is specified within square brackets A dereference maps the elements andor attributes nodes in anode sequence to the nodes that they reference A node sequence passed as an input to the dereference must containelements or attributes of type IDREF or IDREFS The dereference generates a new sequence consisting of the elementnodes whose ID-type attribute values match the IDREF values extracted from the elements and attributes in the inputsequence
The steps of an XPath expression are evaluated from left to right Execution of a step sets the evaluation context items forthe next step A context item in a path expression is a node that is selected as a result of the execution of a step in anXPath expression A step is evaluated relative to the context item that was obtained in the previous step The result of anXPath expression is a sequence of nodes in document order that are obtained after executing all the steps in theexpression in the order from left to right in the path expression
This example expression uses the column Resume which is of type XML in table [HumanResources][JobCandidate] fromthe AdventureWorks database for the purpose of illustrating the concept of path expressions The following pathexpression selects all address nodes for which the address type is set to Home
childnsAddrType[=Home]parentnode()
In the preceding path expression
l child is the axis specifier
l is the axis separator
Copy Code
Copy Code
Copy Code
l ns is the namespace prefix
l AddrType is the node test
l [=Home] is the predicate expression where refers to the context node
XQuery also supports abbreviated syntax for specifying the axis The following table shows the axis and correspondingabbreviated syntax
Table 2 Abbreviated syntax for axes
Example Selecting organization names from employment history
The following XPath expression selects the children text nodes of EmpOrgName elements that are child nodes of nodeResumeEmployment Here text() is used to select the text node of the EmpOrgName element
ResumeEmploymentEmpOrgNametext()
The FLWOR Statement
FLWOR statements form the core expressions of XQuery and are similar to the SELECT statements of SQL The acronymFLWOR (pronounced flower) stands for FOR LET WHERE ORDER BY RETURN FLWOR expressions in XQuery enableusers to specify operations such as declarative iteration variable binding filtering sorting and returning the results SQLServer 2005 supports FOR WHERE ORDER BY and RETURN
For
The for clause in a FLWOR expression enables users to define a declarative iteration of a bound variable over an inputsequence The input sequence can be specified using XPath expressions sequence of atomic values a sequenceconstructed using literals or constructor functions It is therefore analogous to the SQL SELECT FROM clause and is notlike a programming language for construct
Variable binding is also specified in the for clause
Example Selecting all home address elements from resume using the for clause
The following query selects all Address nodes where the type of address is set to Home and the JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddressRESAddrType[=Home]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
where
The where clause filters the results of an iteration by applying the expression specified with the where clause
Example Selecting all home address elements using the where clause
The following query selects all Address nodes where the type of address is set to Home and the JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $ARESAddrType[=Home]
Axis Abbreviated form
Attribute
Child
descendant-or-selfnode()
parentnode()
selfnode()
Copy Code
Copy Code
return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
order by
The order by keyword enables you to sort the values in the returned result set The order by keyword accepts a sortingexpression which should return an atomic value Optionally you can also specify ascending or descending for the sortorder The default sort order is ascending
Example Selecting employment history in ascending order using the order by clause
The following query selects all Employment nodes in ascending order of employment starting date for a candidate whoseJobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentorder by $EMPRESEmpStartDatereturn$EMP
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
return
The return clause which is analogous to the SELECT clause in SQL enables users to define the result of a query You canspecify any valid XQuery expression in the return clause You can also construct XML structures in the return section byspecifying constructors for elements attributes etc
Example Selecting specific elements of employment history using the return clause
The following query selects StartDate EndDate OrgName JobTitle elements of Employment node for a candidate whoseJobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentorder by $EMPRESEmpStartDatereturn
ltEmploymentgt $EMPRESEmpStartDate $EMPRESEmpEndDate $EMPRESEmpOrgName $EMPRESEmpJobTitle
ltEmploymentgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Current implementation of XQuery in SQL Server 2005 does not support the let clause This aspect is discussed further inNon-supported Features and Workarounds in this paper
FLWOR Expressions vs XPath Expressions
Using a FLWOR expression to define the result sequence when the sequence can be expressed using an XPath expressionincurs a performance penalty because the query plan contains a JOIN operation between the for variable and the body ofthe for clause The use of a FLWOR expression is justified only if one or more of the following conditions are satisfied
l If you want to iterate over a sequence of values that are returned as a result of an expression This is achieved usingthe for clause which binds a variable to successive values of the result set Examples are the construction of newelements within the scope of the for clause and the retention of duplicates
l When you want to filter the result sequence of the for clause based on a predicate which cannot be defined using
Copy Code
Copy Code
simple XPath expressions The where clause is used to eliminate unwanted values in the result set An example is asfollows
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(for $i in (1 2 3) $j in (3 4 5)where $i lt $jreturn sum($i + $j)) as Result
l If you want to sort the result set based on a sorting expression Sorting is defined on the result set using the orderby clause
l When you want to define the shape of the returned result set using the results obtained from the for clause Thereturn statement is used to perform the shaping of the result set
In all other cases using XPath expressions is recommended
Operators in XQuery
As a functional language XQuery in SQL Server 2005 supports various types of functions and operators that can begrouped under the following categories
l Arithmetic operators
l Comparison operators
l Logical operators
Table 3 Operators supported in SQL Server 2005
Arithmetic Operators
SQL Server 2005 supports five arithmetic operators These are + b div and mod Currently it does not support idiv
Example Converting selected values of store survey information
This example is based on the [Sales][Store] table in the AdventureWorks database The following query returns values ofAnnualSales AnnualRevenue in yen and the store area in square meters for a store whose CustomerID is 3
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyfor $S in STStoreSurveyreturn
ltStoreDetailsSalesInYen = $SSTAnnualSales1068100 RevenueInYen = $SSTAnnualRevenue1068100 StoreAreaInSqMeters = $SSTSquareFeet00929 gt
ltStoreDetailsgt) as ResultFROM [Sales][Store]WHERE CustomerID = 3
Comparison Operators
Copy Code
Type Operators
Arithmetic operators +-div mod
General comparison operators = = lt gt lt= gt=
Value comparison operators eq ne lt gt le ge
Node comparison operator is
Node order comparison operators gtgt ltlt
Logical operators and or
Copy Code
SQL Server 2005 has implemented support for four types of comparison operatorsmdashgeneral comparison operators valuecomparison operators node comparison operators and node order comparison operators
General comparison operators
General comparison operators help compare atomic values sequences or a combination of the two General comparisonoperators are = = lt gt lt= and gt= A general comparison is existentially quantified meaning that any match willresult in true
Example Selecting all address elements where the address type is not set to Home
The following query selects all Address nodes where the type of address is not set to Home and the JobCandidateID is3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $ARESAddrType[=Home]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Value comparison operators
Value comparison operators help compare atomic values Value comparison operators supported by SQL Server 2005 areeq ne lt gt le and ge The current implementation of XQuery with respect to promoting untyped atomic values is notaligned with the July 2004 draft of the XQuery specification The untyped atomic type is promoted to the type of the otheroperand instead of xsstring as specified in the XQuery specification This is to maintain consistency across general andvalue comparison operators which we consider more important than making the value comparison transitive
Example Selecting all education elements where the GPA is greater than 35
The following query selects all Education nodes where the GPA is greater than 35 for the candidate whoseJobCandidateID is 2
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal($EDRESEduGPA) gt 35return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Node comparison operators
You can use the node comparison operator is to compare two nodes to determine if they represent the same node or notThe node comparison operator accepts two operands that are of type node
Example Comparing two address nodes to check their identity
The following query compares two address nodes to check if they represent the same node in the document
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] is (RESAddress)[1] )then
ltResultgtNodes are equalltResultgtelse
ltResultgtNodes are not equalltResultgt) as ResultFROM [HumanResources][JobCandidate]
Copy Code
Copy Code
Copy Code
WHERE JobCandidateID = 3
Node order comparison operators
You can use the node order comparison operators to ascertain the order of two nodes in a document The node ordercomparison operators supported by SQL Sever 2005 are gtgt and ltlt and both the operators accept two operands The gtgtoperator returns true if the left operand precedes the right operand in document order and the ltlt operator returns trueif the left operand follows the right operand in document order
Example Comparing the order of two address nodes
The following query compares the order of two address nodes for a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddressRESAddrType[=Home])[1] ltlt
(RESResumeRESAddressRESAddrType[=Permanent])[1] )then
ltResultgtHome address precedes Permanent addressltResultgtelse
ltResultgtHome address follows Permanent addressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Logical Operators
The logical operators supported by XQuery in SQL Server 2005 are and and or The value of any logical expressionformed using these operators can be either true or false
Example Using the and operator to create a logical expression
The following query returns the candidates education element that contains bachelor level business degree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[RESEduLevel=Bachelor and RESEduMajor=Business]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
The if-then-else Construct
Like other functional languages XQuery supports the if-then-else construct You can use the if-then-else statement toperform operations based on the value of a conditional expression
Example Using a conditional expression
The following query displays the type of address that is specified in the resume for a candidate whose JobCandidateID is3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddressreturn
if ( $ARESAddrType eq Home )then
ltResultgtHome AddressltResultgtelse
ltResultgtOther AddressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Copy Code
Copy Code
Copy Code
Constructing XML Using XQuery
XQuery constructors enable you to create XML structures within a query Constructors are available for elementsattributes processing instructions text nodes and comments
The following examples illustrate these approaches to constructing XML
Example Using constant expressions
The following query displays employment history details constructed using constant expressions
SELECT Resumequery(ltEmployer IndustryCategory=ITServicesgtltOrganizationgtABC TechnologiesltOrganizationgtltJobTitlegtSoftware EngineerltJobTitlegtltStartDategt2001-10-01ltStartDategtltEndDategt2003-05-09ltEndDategt
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]
WHERE JobCandidateID = 3
Example Using data obtained dynamically
The following query displays employment history details constructed using the results obtained from a query for acandidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmployer Organization = $EMPRESEmpOrgName gt $EMPRESEmpStartDate $EMPRESEmpEndDate $EMPRESEmpJobTitle
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using constant names for computed element and attribute constructors
The following query displays the employment history of a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
element Employerattribute Organization $EMPRESEmpOrgName element StartDate string($EMPRESEmpStartDate) element EndDate string($EMPRESEmpEndDate) element JobTitle string($EMPRESEmpJobTitle)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Performing XQuery Construction vs Shaping Using FOR XML
Some applications have a requirement to generate XML from a rowset On the server XML can be generated using a FORXML clause or XQuery constructions or XML DML operations Recommendations on using FOR XML and XQueryconstructors for constructing XML are as follows
Copy Code
Copy Code
Copy Code
l If XML is to be aggregated from multiple columns and multiple rows then FOR XML is the only choice
l If a single XML instance is to be reshaped then it can be done using XQuery as well as FOR XML XQuery might befaster since the FOR XML approach will require multiple invocations of XML data type methods on the XML instance
l You can use multiple XML DML statements to construct an XML instance This approach is significantly slower thanXQuery construction
l Use the new TYPE directive available with the FOR XML clause in SQL Server 2005 to generate the result of a FORXML query as an instance of XML data type
Built-in XQuery Functions
Implementation of XQuery in SQL Server 2005 supports a subset of the built-in functions of XQuery 10 and XPath 20These functions include data accessor functions string manipulation functions aggregate functions context functionsnumeric functions Boolean functions node functions and sequence functions The following sections explore some ofthese functions
Data Accessors
You can use the data accessor functions to extract values of nodes as strings or typed values XQuery supports two typesof data accessor functions string() which extracts the string value of an item and data() which gets the typed value Ifthe node is not a text node an attribute node or an element node then the data() function throws a static error If thenode is a document node of an untyped XML instance then data() returns a string value of the document The data()function returns a static error if the node is a complex typed element
Example Using the string() function
See the Using constant names for computed element and attribute constructors example in the section Constructing XMLUsing XQuery in this paper for a query that generates the employment history of a candidate by using the string()function and computed element constructors
Example Using the data() function
The following query generates the employment history of a candidate by using the data() function and computed elementconstructors
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) gt 35return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
String Manipulation
XQuery supports four string manipulation functions
l concat() Helps concatenate two or more strings
l contains() Helps determine whether or not a string specified as the first operand contains another string specifiedas the second operand The length of the search string is limited to 4000 Unicode characters
l substring() Helps extract portion of a string from another string known as source string
l string-length() Helps calculate the length of a string
The current release of SQL Server 2005 supports only the Unicode codepoint collation
Example Using the concat() and substring() functions
The following query generates the employment history of a candidate by concatenating the values of start date enddate organization name and job title
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmploymentgtconcat( substring(string($EMPRESEmpStartDate)110) to
substring(string($EMPRESEmpEndDate)110) string($EMPRESEmpOrgName) string($EMPRESEmpJobTitle) )
ltEmploymentgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the contains() function
The following query demonstrates the use of the contains() function by displaying Education details for a node thatcontains the string science in the value of the element EduDegree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere contains($EDRESEduDegree Science)return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Aggregate Functions
Aggregate functions operate on a sequence of items and return the aggregate values of the sequence Aggregate functionscurrently supported in the XQuery support in SQL Server 2005 are count() min() max() avg() and sum() Thefunctions min() and max() accept only base types that support the gt operator (ie the three built-in numeric basetypes the datetime base types xsstring xsboolean and xdtuntypedAtomic) A sequence of mixed types is notsupported in these functions Furthermore xdtuntypedAtomic is treated as xsdouble
For avg() and sum() the type of the passed expression needs to be a subtype of one of the three built-in numeric basetypes or untypedAtomic (but not a mixture xdtuntypedAtomic is treated as xsdouble)
The count() function returns the number of items in a sequence
Example Using the count() function
The following query displays the count of employment education and address elements present in the documentusing the count() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeltEmploymentgtElement count is count(RESResumeRESAddress) ltEmploymentgtltEducationgtElement count is count(RESResumeRESEducation) ltEducationgtltAddressgtElement count is count(RESResumeRESAddress) ltAddressgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the min() function
The following query displays the education element for which the GPA value is minimum using the min() function
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = min(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the max() function
The following query displays the education element for which the GPA value is maximum using the max() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = max(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the avg() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using theavg() function
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt avg(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoNewYorkTempLow) ltAvgLowgt
ltNewYorkgtltBostongt
ltAvgHighgt avg(WeatherInfoBostonTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Example Using the sum() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using the
Copy Code
Copy Code
Copy Code
sum() and count() functions
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt sum(WeatherInfoNewYorkTempHigh) div count
(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt sum(WeatherInfoNewYorkTempLow) div count
(WeatherInfoNewYorkTempLow) ltAvgLowgtltNewYorkgtltBostongt
ltAvgHighgt sum(WeatherInfoBostonTempHigh) div count(WeatherInfoBostonTempHigh) ltAvgHighgt
ltAvgLowgt sum(WeatherInfoBostonTempLow) div count(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Context Functions
You can use the context functions to obtain the contextual properties of a context item SQL Server 2005 implements twocontext functionsmdashlast() and position() The last() function can be used to determine the number of items in asequence and the position() function can be used to obtain the position of a context item Both the last() and position() functions without an argument can only be used in the context of a context-dependent predicate (ie inside []) in SQLServer 2005
Example Using the last() function
The following query retrieves the last address element for a candidate using the last() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[last()]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the position() function
The following query retrieves the first two address elements for a candidate using the position() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[position()lt=2]
) as Result
Copy Code
Copy Code
Copy Code
FROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type-Related Expressions
XQuery supports various types of expressions or operators that are based on the type information These expressions canbe classified as type assertion expressions type inspection expressions and type casting expressions These expressionsare discussed briefly in the following sections
Type Assertion Expressions
as xsTYPE clause in for statement
You can use the as clause to specify the type for the binding variable used in the for statement
When a type is declared for the binding variable binding values that are not of the declared type would result in typeerror The xsTYPE clause is not a cast expression but it serves as a type assertion
Example Using as xsTYPE clause with for statement
The following query binds the address node sequence to a variable $A which is defined as type element(RESAddress)
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A as element(RESAddress) in RESResumeRESAddressreturn
$A) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Type Inspection Expressions
instance of xsTYPE operator
The instance of operator helps identify the runtime type of an item in an XML document
Example Using instance of xsTYPE operator
The following query checks to see if the type of an address node identified by an XPath expression matches element() typeor not
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] instance of element() )then
ltResultgtSelected node is an ElementltResultgtelse
ltResultgtSelected node is not an ElementltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type Casting Expressions
Implicit Type Casting
The XQuery engine performs implicit type casting for numeric types and untypedAtomic values in expressions that containarithmetic operations or function invocations This process is known as type promotion Type promotion occurs when anexpression results in a numeric type that is incompatible with the expected numeric type Type promotion is performed bycasting the resulting expression to the required type
Example Implicit type casting
The following query performs an arithmetic operation on a decimal value and a double value In the current scenario the
Copy Code
Copy Code
values in the expression are added only after promoting the xsdecimal value to xsdouble
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(
ltResultgt xsdecimal(1055) + xsdouble(15e1) ltResultgt) as Result
Explicit Type Casting
Typed value constructors
XQuery provides constructor functions for all built-in types defined in the XML Schema specification These constructorsare useful for constructing typed values and also for casting values from one type to another XQuery also makesconstructors available for types that are defined in imported schemas
Example Using a value constructor for constructing values
The following query returns all Employment nodes for which the StartDate is greater than a value constructed usingconstructor for type xsdate
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentwhere $EMPRESEmpStartDate gt xsdate(1995-01-01)return
$EMP) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using a value constructor for typecasting
The following query selects all Education nodes where the GPA is greater than or equal to 38 for the candidate whoseJobCandidateID is 2 This query uses the value constructor for xsdecimal for typecasting the value of EduGPA fromxsstring to xsdecimal
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) ge 38return
element Educationelement Level string($EDRESEduLevel)element StartDate string($EDRESEduStartDate)element EndDate string($EDRESEduEndDate)element Degree string($EDRESEduDegree)element GPA string($EDRESEduGPA)element GPAScale string($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
cast as xsTYPE Operator
XQuery in SQL Server 2005 supports the cast as TYPE operator which is useful for performing explicit type castingExplicit type casting can also be performed using the xsTYPE() constructors which are more convenient to write thanthe cast as TYPE operator
Example Using cast as xsTYPE operator
The following query generates an XML that contains typed values of selected elements from Education node set for acandidate whose JobCandidateID is 3
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level $EDRESEduLevel cast as xsstring element StartDate $EDRESEduStartDate cast as xsdate element EndDate $EDRESEduEndDate cast as xsdate element Degree $EDRESEduDegree cast as xsstring element GPA $EDRESEduGPA cast as xsdecimal element GPAScale $EDRESEduGPAScale cast as xsdecimal
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using xsTYPE() operator
The following query generates the same results as the query in the previous example using the xsTYPE() operatorinstead of the cast as xsTYPE operator
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level xsstring($EDRESEduLevel) element StartDate xsdate($EDRESEduStartDate) element EndDate xsdate($EDRESEduEndDate) element Degree xsstring($EDRESEduDegree) element GPA xsdecimal($EDRESEduGPA) element GPAScale xsdecimal($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Accessing Relational Columns and Variables
When writing queries using XQuery it is not uncommon to have the requirement for accessing relational columns andvariables from within the query SQL Server 2005 caters to this requirement by implementing two functionsmdashsqlcolumn() and sqlvariable()
The function sqlcolumn() can be used to access non-XML columns in a relational table from within a query This functionis useful for scenarios such as aggregating information from XML and non-XML type columns of one or more tables usingthe values of non-XML columns to filter the results of an XQuery and so on The functions sqlcolumn() andsqlvariable() cannot be used with datetime CLR user-defined functions or XML
Example Using sqlcolumn() function
The following query generates an XML that contains values from the CustomerID and Name columns of non-XML datatype and values of YearOpened NumberOfEmployees AnnualSales and AnnualRevenue elements from theDemographics column
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyelement CustomerInfo
element CustomerID sqlcolumn(StoreCustomerID) element Name sqlcolumn(StoreName) element YearOpened string((STStoreSurveySTYearOpened)[1]) element NumberOfEmployees string((STStoreSurveySTNumberEmployees)[1]) element AnnualSales string((STStoreSurveySTAnnualSales)[1]) element AnnualRevenue string((STStoreSurveySTAnnualRevenue)[1])
) as Result
Copy Code
Copy Code
Copy Code
FROM [Sales][Store] StoreWHERE StoreCustomerID = 4
Example Using sqlvariable() function
The following stored procedure returns home address nodes of a specified candidate by using the value of theAddrType variable in the XQuery where clause to filter the results of the query
CREATE PROCEDURE [GetCandidateAddress]JobCandidateID [int]AddrType [varchar](20)
ASBEGIN
SET NOCOUNT ON
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $A[ RESAddrType = sqlvariable(AddrType) ]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = JobCandidateID
END
Example Using sqlvariable() function in conjunction with the exist() method of the XML data type
The following query returns resumes of candidates who hold a Bachelors degree with a major in Business
DECLARE EducationLevel varchar(20)SET EducationLevel = Bachelor
DECLARE Major varchar(20)SET Major = Business
SELECT JobCandidateID ResumeFROM [HumanResources][JobCandidate]WHERE Resumeexist (
declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[ RESEduLevel = sqlvariable(EducationLevel) and RESEduMajor
= sqlvariable(Major) ]) = 1
Non-Supported Features and Workarounds
Current implementation of XQuery in SQL Server 2005 does not support the following features
l The let clause The let clause which is a part of the FLWOR expression is useful for binding a variable to the resultsof an expression WorkaroundmdashInstead of using the let clause use an inline expression
l Range expression (to operator) A range expression can be used to construct a sequence of consecutive integersusing the to operator For example using a range expression such as (6 to 10) it is possible to construct thesequence (6 7 8 9 10) WorkaroundmdashInstead of using the to operator list all items in your sequence
l Type information Some features that are based on type system such as typeswitch treat as castable andvalidate expressions are currently not supported
l The functionality of a typeswitch expression is similar to the switch-case construct available in otherprogramming languages In a switch-case statement the branchescases are selected based on the value of theargument passed to the switch In a typeswitch expression the branches are selected based on the type of theargument passed to typeswitch Workaroundmdashuse if then else and instance of
l The treat as expression can be used to change the static type of the result of an expression to a specific statictype and raises a static type error if the static type of the expression does not match the specified type It doesnot change the dynamic type or value of the expression Workaroundmdashnone
l The castable expression is useful for checking whether an atomic value can be cast to the specified typeWorkaroundmdashInstead of using the expression $x castable as T use the expression empty(data($x)) or not(empty(T($x)))
Copy Code
Copy Code
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
l When queries are written in XQuery they require less code as compared to queries written in XSLT
l XQuery can be used as a strongly typed language when the XML data is typed which can improve the performanceof the query by avoiding implicit type casts and provide type assurances that can be used when performing queryoptimization
l XQuery can be used as a weakly typed language for untyped data to provide high usability SQL Server 2005implements static type inferencing with support for both strong and weak type relationships
l Because XQuery requires less code to perform a query than does XSLT maintenance costs are lower
l XQuery is going to be a W3C recommendation and will be supported by major database vendors
Caveat regarding XQuery 10 language as of the writing of this document
l The XQuery specification is currently under development and may change in the future SQL Server 2005 implementsa stable part of the W3C working draft
Application Areas of XQuery
Application areas of XQuery can be classified broadly as follows
l XQuery for queryanalysis XQuery is excellent for querying huge chunks of data and provides the capability tofilter sort order and repurpose the required information Typical applications include querying XML documents thatrepresent semi-structured information name-value pair property bags analysis of application logs transaction logsand audit logs to identify potential application errors and security issues and so on
l XQuery for application integration As organizations move away from proprietary application integrationapproaches and start adopting standards based application integration approaches the need for transforming datafrom internal application-specific formats to standard exchange formats is gaining more focus Because of its abilityto construct and transform XML data XQuery caters to this need One typical use of XQuery in the application-integration domain is translating the vocabulary used by one application that uses native XML databaserelationaldata source into a language used by another application that uses XMLrelational data format
Advantages of Using XQuery at the Server
Performing XML processing at the server using XQuery has many advantages compared to client-side XML processingSome of these advantages can be summarized as follows
l Reduced traffic on the network When XML data is processed on the server only the results are forwarded to theclient This results in reduced traffic on the network
l More security Only the data that is required is sent to the client thereby avoiding the risk of exposing the entiredata to the network as is the case when using client-side XML processing
l Better maintainability Processing XML on the server results in browser independent code on the client whichleads to better maintainability on the client side
l Improved performance Queries written using XQuery on the server are subjected to optimization by the SQLquery engine This results in improved performance when compared to retrieving the entire data and filtering thedata at the client Furthermore indexes can be created on the XML data type column to achieve enhancedperformance
How XQuery Implementation Uses XML Schemas
The XML schema collection associated with an XML data type is used by the relational engine as follows
l To validate the XML instances during insertion operations
l To validate the XML instances during modification operations
l Type information contained in the XML schema is used during static type checking for early error detection and forquery performance improvements by generating better query plans and avoiding many runtime inspections
l Type information present in the XML schema is used by the SQL Server to optimize storage
Structure of the XQuery Expression
An XQuery expression in SQL Server 2005 consists of two sectionsmdasha prolog and a body A prolog can in turn contain anamespace declaration subsection Namespace declarations are used to define a mapping between prefix and namespaceURI thereby enabling you to use the prefix instead of the namespace URI in the query body You can also refer to elementnames without the prefix by binding a default namespace for element names using the declare default namespacedeclaration
The body of an XQuery expression contains query expressions that define the result of the query It can for example bethe signature FLWOR expression (see The FLWOR Statement in this paper) an XPath 20 expression (see XPath 20
Expressions in this paper) or another XQuery expression such as a construction or arithmetic expression
Example Specifying default namespace in prolog section of XQuery
The following query selects all Employment nodes for a candidate whose JobCandidateID is 3 The query defines adefault namespace and does not use a namespace prefix
SELECT Resumequery(declare default namespace httpschemasmicrosoftcomsqlserver200407adventure-
worksResumeResumeEmployment
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Specifying namespace using the WITH XMLNAMESPACES clause
SQL Server also supports the SQL-2003 standard extension that allows a user to declare XML namespace bindings in theSQL WITH clause on a per SQL query basis thus avoiding repetitive declarations in multiple XML data type methodinvocations The following query shows the modified version of the query shown in the previous example This querydeclares a namespace using the WITH XMLNAMESPACES clause
WITH XMLNAMESPACES( httpschemasmicrosoftcomsqlserver200407adventure-worksResumeAS RES)SELECT Resumequery(
RESResumeRESEmployment) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
XPath 20 Expressions
XQuery uses XPath 20 expressions to locate nodes in a document and to navigate from one location to another within asingle document or across documents Navigation paths defined using XPath consist of a sequence of steps separated by A single step comprises an axis a node test and zero or more step qualifiers
The axis specifies the direction of movement relative to the context node Supported axes in SQL Server 2005 are childdescendant parent attribute self and descendant-or-self
A node test specifies a condition that all the nodes that are selected by a step must satisfy The node condition can bespecified based on node name or node type
Step qualifiers can be defined by using predicates or dereferences A predicate is an expression that acts as a filter on anode sequence and is specified within square brackets A dereference maps the elements andor attributes nodes in anode sequence to the nodes that they reference A node sequence passed as an input to the dereference must containelements or attributes of type IDREF or IDREFS The dereference generates a new sequence consisting of the elementnodes whose ID-type attribute values match the IDREF values extracted from the elements and attributes in the inputsequence
The steps of an XPath expression are evaluated from left to right Execution of a step sets the evaluation context items forthe next step A context item in a path expression is a node that is selected as a result of the execution of a step in anXPath expression A step is evaluated relative to the context item that was obtained in the previous step The result of anXPath expression is a sequence of nodes in document order that are obtained after executing all the steps in theexpression in the order from left to right in the path expression
This example expression uses the column Resume which is of type XML in table [HumanResources][JobCandidate] fromthe AdventureWorks database for the purpose of illustrating the concept of path expressions The following pathexpression selects all address nodes for which the address type is set to Home
childnsAddrType[=Home]parentnode()
In the preceding path expression
l child is the axis specifier
l is the axis separator
Copy Code
Copy Code
Copy Code
l ns is the namespace prefix
l AddrType is the node test
l [=Home] is the predicate expression where refers to the context node
XQuery also supports abbreviated syntax for specifying the axis The following table shows the axis and correspondingabbreviated syntax
Table 2 Abbreviated syntax for axes
Example Selecting organization names from employment history
The following XPath expression selects the children text nodes of EmpOrgName elements that are child nodes of nodeResumeEmployment Here text() is used to select the text node of the EmpOrgName element
ResumeEmploymentEmpOrgNametext()
The FLWOR Statement
FLWOR statements form the core expressions of XQuery and are similar to the SELECT statements of SQL The acronymFLWOR (pronounced flower) stands for FOR LET WHERE ORDER BY RETURN FLWOR expressions in XQuery enableusers to specify operations such as declarative iteration variable binding filtering sorting and returning the results SQLServer 2005 supports FOR WHERE ORDER BY and RETURN
For
The for clause in a FLWOR expression enables users to define a declarative iteration of a bound variable over an inputsequence The input sequence can be specified using XPath expressions sequence of atomic values a sequenceconstructed using literals or constructor functions It is therefore analogous to the SQL SELECT FROM clause and is notlike a programming language for construct
Variable binding is also specified in the for clause
Example Selecting all home address elements from resume using the for clause
The following query selects all Address nodes where the type of address is set to Home and the JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddressRESAddrType[=Home]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
where
The where clause filters the results of an iteration by applying the expression specified with the where clause
Example Selecting all home address elements using the where clause
The following query selects all Address nodes where the type of address is set to Home and the JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $ARESAddrType[=Home]
Axis Abbreviated form
Attribute
Child
descendant-or-selfnode()
parentnode()
selfnode()
Copy Code
Copy Code
return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
order by
The order by keyword enables you to sort the values in the returned result set The order by keyword accepts a sortingexpression which should return an atomic value Optionally you can also specify ascending or descending for the sortorder The default sort order is ascending
Example Selecting employment history in ascending order using the order by clause
The following query selects all Employment nodes in ascending order of employment starting date for a candidate whoseJobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentorder by $EMPRESEmpStartDatereturn$EMP
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
return
The return clause which is analogous to the SELECT clause in SQL enables users to define the result of a query You canspecify any valid XQuery expression in the return clause You can also construct XML structures in the return section byspecifying constructors for elements attributes etc
Example Selecting specific elements of employment history using the return clause
The following query selects StartDate EndDate OrgName JobTitle elements of Employment node for a candidate whoseJobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentorder by $EMPRESEmpStartDatereturn
ltEmploymentgt $EMPRESEmpStartDate $EMPRESEmpEndDate $EMPRESEmpOrgName $EMPRESEmpJobTitle
ltEmploymentgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Current implementation of XQuery in SQL Server 2005 does not support the let clause This aspect is discussed further inNon-supported Features and Workarounds in this paper
FLWOR Expressions vs XPath Expressions
Using a FLWOR expression to define the result sequence when the sequence can be expressed using an XPath expressionincurs a performance penalty because the query plan contains a JOIN operation between the for variable and the body ofthe for clause The use of a FLWOR expression is justified only if one or more of the following conditions are satisfied
l If you want to iterate over a sequence of values that are returned as a result of an expression This is achieved usingthe for clause which binds a variable to successive values of the result set Examples are the construction of newelements within the scope of the for clause and the retention of duplicates
l When you want to filter the result sequence of the for clause based on a predicate which cannot be defined using
Copy Code
Copy Code
simple XPath expressions The where clause is used to eliminate unwanted values in the result set An example is asfollows
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(for $i in (1 2 3) $j in (3 4 5)where $i lt $jreturn sum($i + $j)) as Result
l If you want to sort the result set based on a sorting expression Sorting is defined on the result set using the orderby clause
l When you want to define the shape of the returned result set using the results obtained from the for clause Thereturn statement is used to perform the shaping of the result set
In all other cases using XPath expressions is recommended
Operators in XQuery
As a functional language XQuery in SQL Server 2005 supports various types of functions and operators that can begrouped under the following categories
l Arithmetic operators
l Comparison operators
l Logical operators
Table 3 Operators supported in SQL Server 2005
Arithmetic Operators
SQL Server 2005 supports five arithmetic operators These are + b div and mod Currently it does not support idiv
Example Converting selected values of store survey information
This example is based on the [Sales][Store] table in the AdventureWorks database The following query returns values ofAnnualSales AnnualRevenue in yen and the store area in square meters for a store whose CustomerID is 3
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyfor $S in STStoreSurveyreturn
ltStoreDetailsSalesInYen = $SSTAnnualSales1068100 RevenueInYen = $SSTAnnualRevenue1068100 StoreAreaInSqMeters = $SSTSquareFeet00929 gt
ltStoreDetailsgt) as ResultFROM [Sales][Store]WHERE CustomerID = 3
Comparison Operators
Copy Code
Type Operators
Arithmetic operators +-div mod
General comparison operators = = lt gt lt= gt=
Value comparison operators eq ne lt gt le ge
Node comparison operator is
Node order comparison operators gtgt ltlt
Logical operators and or
Copy Code
SQL Server 2005 has implemented support for four types of comparison operatorsmdashgeneral comparison operators valuecomparison operators node comparison operators and node order comparison operators
General comparison operators
General comparison operators help compare atomic values sequences or a combination of the two General comparisonoperators are = = lt gt lt= and gt= A general comparison is existentially quantified meaning that any match willresult in true
Example Selecting all address elements where the address type is not set to Home
The following query selects all Address nodes where the type of address is not set to Home and the JobCandidateID is3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $ARESAddrType[=Home]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Value comparison operators
Value comparison operators help compare atomic values Value comparison operators supported by SQL Server 2005 areeq ne lt gt le and ge The current implementation of XQuery with respect to promoting untyped atomic values is notaligned with the July 2004 draft of the XQuery specification The untyped atomic type is promoted to the type of the otheroperand instead of xsstring as specified in the XQuery specification This is to maintain consistency across general andvalue comparison operators which we consider more important than making the value comparison transitive
Example Selecting all education elements where the GPA is greater than 35
The following query selects all Education nodes where the GPA is greater than 35 for the candidate whoseJobCandidateID is 2
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal($EDRESEduGPA) gt 35return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Node comparison operators
You can use the node comparison operator is to compare two nodes to determine if they represent the same node or notThe node comparison operator accepts two operands that are of type node
Example Comparing two address nodes to check their identity
The following query compares two address nodes to check if they represent the same node in the document
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] is (RESAddress)[1] )then
ltResultgtNodes are equalltResultgtelse
ltResultgtNodes are not equalltResultgt) as ResultFROM [HumanResources][JobCandidate]
Copy Code
Copy Code
Copy Code
WHERE JobCandidateID = 3
Node order comparison operators
You can use the node order comparison operators to ascertain the order of two nodes in a document The node ordercomparison operators supported by SQL Sever 2005 are gtgt and ltlt and both the operators accept two operands The gtgtoperator returns true if the left operand precedes the right operand in document order and the ltlt operator returns trueif the left operand follows the right operand in document order
Example Comparing the order of two address nodes
The following query compares the order of two address nodes for a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddressRESAddrType[=Home])[1] ltlt
(RESResumeRESAddressRESAddrType[=Permanent])[1] )then
ltResultgtHome address precedes Permanent addressltResultgtelse
ltResultgtHome address follows Permanent addressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Logical Operators
The logical operators supported by XQuery in SQL Server 2005 are and and or The value of any logical expressionformed using these operators can be either true or false
Example Using the and operator to create a logical expression
The following query returns the candidates education element that contains bachelor level business degree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[RESEduLevel=Bachelor and RESEduMajor=Business]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
The if-then-else Construct
Like other functional languages XQuery supports the if-then-else construct You can use the if-then-else statement toperform operations based on the value of a conditional expression
Example Using a conditional expression
The following query displays the type of address that is specified in the resume for a candidate whose JobCandidateID is3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddressreturn
if ( $ARESAddrType eq Home )then
ltResultgtHome AddressltResultgtelse
ltResultgtOther AddressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Copy Code
Copy Code
Copy Code
Constructing XML Using XQuery
XQuery constructors enable you to create XML structures within a query Constructors are available for elementsattributes processing instructions text nodes and comments
The following examples illustrate these approaches to constructing XML
Example Using constant expressions
The following query displays employment history details constructed using constant expressions
SELECT Resumequery(ltEmployer IndustryCategory=ITServicesgtltOrganizationgtABC TechnologiesltOrganizationgtltJobTitlegtSoftware EngineerltJobTitlegtltStartDategt2001-10-01ltStartDategtltEndDategt2003-05-09ltEndDategt
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]
WHERE JobCandidateID = 3
Example Using data obtained dynamically
The following query displays employment history details constructed using the results obtained from a query for acandidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmployer Organization = $EMPRESEmpOrgName gt $EMPRESEmpStartDate $EMPRESEmpEndDate $EMPRESEmpJobTitle
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using constant names for computed element and attribute constructors
The following query displays the employment history of a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
element Employerattribute Organization $EMPRESEmpOrgName element StartDate string($EMPRESEmpStartDate) element EndDate string($EMPRESEmpEndDate) element JobTitle string($EMPRESEmpJobTitle)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Performing XQuery Construction vs Shaping Using FOR XML
Some applications have a requirement to generate XML from a rowset On the server XML can be generated using a FORXML clause or XQuery constructions or XML DML operations Recommendations on using FOR XML and XQueryconstructors for constructing XML are as follows
Copy Code
Copy Code
Copy Code
l If XML is to be aggregated from multiple columns and multiple rows then FOR XML is the only choice
l If a single XML instance is to be reshaped then it can be done using XQuery as well as FOR XML XQuery might befaster since the FOR XML approach will require multiple invocations of XML data type methods on the XML instance
l You can use multiple XML DML statements to construct an XML instance This approach is significantly slower thanXQuery construction
l Use the new TYPE directive available with the FOR XML clause in SQL Server 2005 to generate the result of a FORXML query as an instance of XML data type
Built-in XQuery Functions
Implementation of XQuery in SQL Server 2005 supports a subset of the built-in functions of XQuery 10 and XPath 20These functions include data accessor functions string manipulation functions aggregate functions context functionsnumeric functions Boolean functions node functions and sequence functions The following sections explore some ofthese functions
Data Accessors
You can use the data accessor functions to extract values of nodes as strings or typed values XQuery supports two typesof data accessor functions string() which extracts the string value of an item and data() which gets the typed value Ifthe node is not a text node an attribute node or an element node then the data() function throws a static error If thenode is a document node of an untyped XML instance then data() returns a string value of the document The data()function returns a static error if the node is a complex typed element
Example Using the string() function
See the Using constant names for computed element and attribute constructors example in the section Constructing XMLUsing XQuery in this paper for a query that generates the employment history of a candidate by using the string()function and computed element constructors
Example Using the data() function
The following query generates the employment history of a candidate by using the data() function and computed elementconstructors
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) gt 35return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
String Manipulation
XQuery supports four string manipulation functions
l concat() Helps concatenate two or more strings
l contains() Helps determine whether or not a string specified as the first operand contains another string specifiedas the second operand The length of the search string is limited to 4000 Unicode characters
l substring() Helps extract portion of a string from another string known as source string
l string-length() Helps calculate the length of a string
The current release of SQL Server 2005 supports only the Unicode codepoint collation
Example Using the concat() and substring() functions
The following query generates the employment history of a candidate by concatenating the values of start date enddate organization name and job title
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmploymentgtconcat( substring(string($EMPRESEmpStartDate)110) to
substring(string($EMPRESEmpEndDate)110) string($EMPRESEmpOrgName) string($EMPRESEmpJobTitle) )
ltEmploymentgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the contains() function
The following query demonstrates the use of the contains() function by displaying Education details for a node thatcontains the string science in the value of the element EduDegree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere contains($EDRESEduDegree Science)return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Aggregate Functions
Aggregate functions operate on a sequence of items and return the aggregate values of the sequence Aggregate functionscurrently supported in the XQuery support in SQL Server 2005 are count() min() max() avg() and sum() Thefunctions min() and max() accept only base types that support the gt operator (ie the three built-in numeric basetypes the datetime base types xsstring xsboolean and xdtuntypedAtomic) A sequence of mixed types is notsupported in these functions Furthermore xdtuntypedAtomic is treated as xsdouble
For avg() and sum() the type of the passed expression needs to be a subtype of one of the three built-in numeric basetypes or untypedAtomic (but not a mixture xdtuntypedAtomic is treated as xsdouble)
The count() function returns the number of items in a sequence
Example Using the count() function
The following query displays the count of employment education and address elements present in the documentusing the count() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeltEmploymentgtElement count is count(RESResumeRESAddress) ltEmploymentgtltEducationgtElement count is count(RESResumeRESEducation) ltEducationgtltAddressgtElement count is count(RESResumeRESAddress) ltAddressgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the min() function
The following query displays the education element for which the GPA value is minimum using the min() function
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = min(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the max() function
The following query displays the education element for which the GPA value is maximum using the max() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = max(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the avg() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using theavg() function
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt avg(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoNewYorkTempLow) ltAvgLowgt
ltNewYorkgtltBostongt
ltAvgHighgt avg(WeatherInfoBostonTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Example Using the sum() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using the
Copy Code
Copy Code
Copy Code
sum() and count() functions
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt sum(WeatherInfoNewYorkTempHigh) div count
(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt sum(WeatherInfoNewYorkTempLow) div count
(WeatherInfoNewYorkTempLow) ltAvgLowgtltNewYorkgtltBostongt
ltAvgHighgt sum(WeatherInfoBostonTempHigh) div count(WeatherInfoBostonTempHigh) ltAvgHighgt
ltAvgLowgt sum(WeatherInfoBostonTempLow) div count(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Context Functions
You can use the context functions to obtain the contextual properties of a context item SQL Server 2005 implements twocontext functionsmdashlast() and position() The last() function can be used to determine the number of items in asequence and the position() function can be used to obtain the position of a context item Both the last() and position() functions without an argument can only be used in the context of a context-dependent predicate (ie inside []) in SQLServer 2005
Example Using the last() function
The following query retrieves the last address element for a candidate using the last() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[last()]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the position() function
The following query retrieves the first two address elements for a candidate using the position() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[position()lt=2]
) as Result
Copy Code
Copy Code
Copy Code
FROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type-Related Expressions
XQuery supports various types of expressions or operators that are based on the type information These expressions canbe classified as type assertion expressions type inspection expressions and type casting expressions These expressionsare discussed briefly in the following sections
Type Assertion Expressions
as xsTYPE clause in for statement
You can use the as clause to specify the type for the binding variable used in the for statement
When a type is declared for the binding variable binding values that are not of the declared type would result in typeerror The xsTYPE clause is not a cast expression but it serves as a type assertion
Example Using as xsTYPE clause with for statement
The following query binds the address node sequence to a variable $A which is defined as type element(RESAddress)
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A as element(RESAddress) in RESResumeRESAddressreturn
$A) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Type Inspection Expressions
instance of xsTYPE operator
The instance of operator helps identify the runtime type of an item in an XML document
Example Using instance of xsTYPE operator
The following query checks to see if the type of an address node identified by an XPath expression matches element() typeor not
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] instance of element() )then
ltResultgtSelected node is an ElementltResultgtelse
ltResultgtSelected node is not an ElementltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type Casting Expressions
Implicit Type Casting
The XQuery engine performs implicit type casting for numeric types and untypedAtomic values in expressions that containarithmetic operations or function invocations This process is known as type promotion Type promotion occurs when anexpression results in a numeric type that is incompatible with the expected numeric type Type promotion is performed bycasting the resulting expression to the required type
Example Implicit type casting
The following query performs an arithmetic operation on a decimal value and a double value In the current scenario the
Copy Code
Copy Code
values in the expression are added only after promoting the xsdecimal value to xsdouble
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(
ltResultgt xsdecimal(1055) + xsdouble(15e1) ltResultgt) as Result
Explicit Type Casting
Typed value constructors
XQuery provides constructor functions for all built-in types defined in the XML Schema specification These constructorsare useful for constructing typed values and also for casting values from one type to another XQuery also makesconstructors available for types that are defined in imported schemas
Example Using a value constructor for constructing values
The following query returns all Employment nodes for which the StartDate is greater than a value constructed usingconstructor for type xsdate
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentwhere $EMPRESEmpStartDate gt xsdate(1995-01-01)return
$EMP) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using a value constructor for typecasting
The following query selects all Education nodes where the GPA is greater than or equal to 38 for the candidate whoseJobCandidateID is 2 This query uses the value constructor for xsdecimal for typecasting the value of EduGPA fromxsstring to xsdecimal
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) ge 38return
element Educationelement Level string($EDRESEduLevel)element StartDate string($EDRESEduStartDate)element EndDate string($EDRESEduEndDate)element Degree string($EDRESEduDegree)element GPA string($EDRESEduGPA)element GPAScale string($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
cast as xsTYPE Operator
XQuery in SQL Server 2005 supports the cast as TYPE operator which is useful for performing explicit type castingExplicit type casting can also be performed using the xsTYPE() constructors which are more convenient to write thanthe cast as TYPE operator
Example Using cast as xsTYPE operator
The following query generates an XML that contains typed values of selected elements from Education node set for acandidate whose JobCandidateID is 3
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level $EDRESEduLevel cast as xsstring element StartDate $EDRESEduStartDate cast as xsdate element EndDate $EDRESEduEndDate cast as xsdate element Degree $EDRESEduDegree cast as xsstring element GPA $EDRESEduGPA cast as xsdecimal element GPAScale $EDRESEduGPAScale cast as xsdecimal
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using xsTYPE() operator
The following query generates the same results as the query in the previous example using the xsTYPE() operatorinstead of the cast as xsTYPE operator
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level xsstring($EDRESEduLevel) element StartDate xsdate($EDRESEduStartDate) element EndDate xsdate($EDRESEduEndDate) element Degree xsstring($EDRESEduDegree) element GPA xsdecimal($EDRESEduGPA) element GPAScale xsdecimal($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Accessing Relational Columns and Variables
When writing queries using XQuery it is not uncommon to have the requirement for accessing relational columns andvariables from within the query SQL Server 2005 caters to this requirement by implementing two functionsmdashsqlcolumn() and sqlvariable()
The function sqlcolumn() can be used to access non-XML columns in a relational table from within a query This functionis useful for scenarios such as aggregating information from XML and non-XML type columns of one or more tables usingthe values of non-XML columns to filter the results of an XQuery and so on The functions sqlcolumn() andsqlvariable() cannot be used with datetime CLR user-defined functions or XML
Example Using sqlcolumn() function
The following query generates an XML that contains values from the CustomerID and Name columns of non-XML datatype and values of YearOpened NumberOfEmployees AnnualSales and AnnualRevenue elements from theDemographics column
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyelement CustomerInfo
element CustomerID sqlcolumn(StoreCustomerID) element Name sqlcolumn(StoreName) element YearOpened string((STStoreSurveySTYearOpened)[1]) element NumberOfEmployees string((STStoreSurveySTNumberEmployees)[1]) element AnnualSales string((STStoreSurveySTAnnualSales)[1]) element AnnualRevenue string((STStoreSurveySTAnnualRevenue)[1])
) as Result
Copy Code
Copy Code
Copy Code
FROM [Sales][Store] StoreWHERE StoreCustomerID = 4
Example Using sqlvariable() function
The following stored procedure returns home address nodes of a specified candidate by using the value of theAddrType variable in the XQuery where clause to filter the results of the query
CREATE PROCEDURE [GetCandidateAddress]JobCandidateID [int]AddrType [varchar](20)
ASBEGIN
SET NOCOUNT ON
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $A[ RESAddrType = sqlvariable(AddrType) ]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = JobCandidateID
END
Example Using sqlvariable() function in conjunction with the exist() method of the XML data type
The following query returns resumes of candidates who hold a Bachelors degree with a major in Business
DECLARE EducationLevel varchar(20)SET EducationLevel = Bachelor
DECLARE Major varchar(20)SET Major = Business
SELECT JobCandidateID ResumeFROM [HumanResources][JobCandidate]WHERE Resumeexist (
declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[ RESEduLevel = sqlvariable(EducationLevel) and RESEduMajor
= sqlvariable(Major) ]) = 1
Non-Supported Features and Workarounds
Current implementation of XQuery in SQL Server 2005 does not support the following features
l The let clause The let clause which is a part of the FLWOR expression is useful for binding a variable to the resultsof an expression WorkaroundmdashInstead of using the let clause use an inline expression
l Range expression (to operator) A range expression can be used to construct a sequence of consecutive integersusing the to operator For example using a range expression such as (6 to 10) it is possible to construct thesequence (6 7 8 9 10) WorkaroundmdashInstead of using the to operator list all items in your sequence
l Type information Some features that are based on type system such as typeswitch treat as castable andvalidate expressions are currently not supported
l The functionality of a typeswitch expression is similar to the switch-case construct available in otherprogramming languages In a switch-case statement the branchescases are selected based on the value of theargument passed to the switch In a typeswitch expression the branches are selected based on the type of theargument passed to typeswitch Workaroundmdashuse if then else and instance of
l The treat as expression can be used to change the static type of the result of an expression to a specific statictype and raises a static type error if the static type of the expression does not match the specified type It doesnot change the dynamic type or value of the expression Workaroundmdashnone
l The castable expression is useful for checking whether an atomic value can be cast to the specified typeWorkaroundmdashInstead of using the expression $x castable as T use the expression empty(data($x)) or not(empty(T($x)))
Copy Code
Copy Code
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
Expressions in this paper) or another XQuery expression such as a construction or arithmetic expression
Example Specifying default namespace in prolog section of XQuery
The following query selects all Employment nodes for a candidate whose JobCandidateID is 3 The query defines adefault namespace and does not use a namespace prefix
SELECT Resumequery(declare default namespace httpschemasmicrosoftcomsqlserver200407adventure-
worksResumeResumeEmployment
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Specifying namespace using the WITH XMLNAMESPACES clause
SQL Server also supports the SQL-2003 standard extension that allows a user to declare XML namespace bindings in theSQL WITH clause on a per SQL query basis thus avoiding repetitive declarations in multiple XML data type methodinvocations The following query shows the modified version of the query shown in the previous example This querydeclares a namespace using the WITH XMLNAMESPACES clause
WITH XMLNAMESPACES( httpschemasmicrosoftcomsqlserver200407adventure-worksResumeAS RES)SELECT Resumequery(
RESResumeRESEmployment) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
XPath 20 Expressions
XQuery uses XPath 20 expressions to locate nodes in a document and to navigate from one location to another within asingle document or across documents Navigation paths defined using XPath consist of a sequence of steps separated by A single step comprises an axis a node test and zero or more step qualifiers
The axis specifies the direction of movement relative to the context node Supported axes in SQL Server 2005 are childdescendant parent attribute self and descendant-or-self
A node test specifies a condition that all the nodes that are selected by a step must satisfy The node condition can bespecified based on node name or node type
Step qualifiers can be defined by using predicates or dereferences A predicate is an expression that acts as a filter on anode sequence and is specified within square brackets A dereference maps the elements andor attributes nodes in anode sequence to the nodes that they reference A node sequence passed as an input to the dereference must containelements or attributes of type IDREF or IDREFS The dereference generates a new sequence consisting of the elementnodes whose ID-type attribute values match the IDREF values extracted from the elements and attributes in the inputsequence
The steps of an XPath expression are evaluated from left to right Execution of a step sets the evaluation context items forthe next step A context item in a path expression is a node that is selected as a result of the execution of a step in anXPath expression A step is evaluated relative to the context item that was obtained in the previous step The result of anXPath expression is a sequence of nodes in document order that are obtained after executing all the steps in theexpression in the order from left to right in the path expression
This example expression uses the column Resume which is of type XML in table [HumanResources][JobCandidate] fromthe AdventureWorks database for the purpose of illustrating the concept of path expressions The following pathexpression selects all address nodes for which the address type is set to Home
childnsAddrType[=Home]parentnode()
In the preceding path expression
l child is the axis specifier
l is the axis separator
Copy Code
Copy Code
Copy Code
l ns is the namespace prefix
l AddrType is the node test
l [=Home] is the predicate expression where refers to the context node
XQuery also supports abbreviated syntax for specifying the axis The following table shows the axis and correspondingabbreviated syntax
Table 2 Abbreviated syntax for axes
Example Selecting organization names from employment history
The following XPath expression selects the children text nodes of EmpOrgName elements that are child nodes of nodeResumeEmployment Here text() is used to select the text node of the EmpOrgName element
ResumeEmploymentEmpOrgNametext()
The FLWOR Statement
FLWOR statements form the core expressions of XQuery and are similar to the SELECT statements of SQL The acronymFLWOR (pronounced flower) stands for FOR LET WHERE ORDER BY RETURN FLWOR expressions in XQuery enableusers to specify operations such as declarative iteration variable binding filtering sorting and returning the results SQLServer 2005 supports FOR WHERE ORDER BY and RETURN
For
The for clause in a FLWOR expression enables users to define a declarative iteration of a bound variable over an inputsequence The input sequence can be specified using XPath expressions sequence of atomic values a sequenceconstructed using literals or constructor functions It is therefore analogous to the SQL SELECT FROM clause and is notlike a programming language for construct
Variable binding is also specified in the for clause
Example Selecting all home address elements from resume using the for clause
The following query selects all Address nodes where the type of address is set to Home and the JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddressRESAddrType[=Home]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
where
The where clause filters the results of an iteration by applying the expression specified with the where clause
Example Selecting all home address elements using the where clause
The following query selects all Address nodes where the type of address is set to Home and the JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $ARESAddrType[=Home]
Axis Abbreviated form
Attribute
Child
descendant-or-selfnode()
parentnode()
selfnode()
Copy Code
Copy Code
return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
order by
The order by keyword enables you to sort the values in the returned result set The order by keyword accepts a sortingexpression which should return an atomic value Optionally you can also specify ascending or descending for the sortorder The default sort order is ascending
Example Selecting employment history in ascending order using the order by clause
The following query selects all Employment nodes in ascending order of employment starting date for a candidate whoseJobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentorder by $EMPRESEmpStartDatereturn$EMP
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
return
The return clause which is analogous to the SELECT clause in SQL enables users to define the result of a query You canspecify any valid XQuery expression in the return clause You can also construct XML structures in the return section byspecifying constructors for elements attributes etc
Example Selecting specific elements of employment history using the return clause
The following query selects StartDate EndDate OrgName JobTitle elements of Employment node for a candidate whoseJobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentorder by $EMPRESEmpStartDatereturn
ltEmploymentgt $EMPRESEmpStartDate $EMPRESEmpEndDate $EMPRESEmpOrgName $EMPRESEmpJobTitle
ltEmploymentgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Current implementation of XQuery in SQL Server 2005 does not support the let clause This aspect is discussed further inNon-supported Features and Workarounds in this paper
FLWOR Expressions vs XPath Expressions
Using a FLWOR expression to define the result sequence when the sequence can be expressed using an XPath expressionincurs a performance penalty because the query plan contains a JOIN operation between the for variable and the body ofthe for clause The use of a FLWOR expression is justified only if one or more of the following conditions are satisfied
l If you want to iterate over a sequence of values that are returned as a result of an expression This is achieved usingthe for clause which binds a variable to successive values of the result set Examples are the construction of newelements within the scope of the for clause and the retention of duplicates
l When you want to filter the result sequence of the for clause based on a predicate which cannot be defined using
Copy Code
Copy Code
simple XPath expressions The where clause is used to eliminate unwanted values in the result set An example is asfollows
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(for $i in (1 2 3) $j in (3 4 5)where $i lt $jreturn sum($i + $j)) as Result
l If you want to sort the result set based on a sorting expression Sorting is defined on the result set using the orderby clause
l When you want to define the shape of the returned result set using the results obtained from the for clause Thereturn statement is used to perform the shaping of the result set
In all other cases using XPath expressions is recommended
Operators in XQuery
As a functional language XQuery in SQL Server 2005 supports various types of functions and operators that can begrouped under the following categories
l Arithmetic operators
l Comparison operators
l Logical operators
Table 3 Operators supported in SQL Server 2005
Arithmetic Operators
SQL Server 2005 supports five arithmetic operators These are + b div and mod Currently it does not support idiv
Example Converting selected values of store survey information
This example is based on the [Sales][Store] table in the AdventureWorks database The following query returns values ofAnnualSales AnnualRevenue in yen and the store area in square meters for a store whose CustomerID is 3
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyfor $S in STStoreSurveyreturn
ltStoreDetailsSalesInYen = $SSTAnnualSales1068100 RevenueInYen = $SSTAnnualRevenue1068100 StoreAreaInSqMeters = $SSTSquareFeet00929 gt
ltStoreDetailsgt) as ResultFROM [Sales][Store]WHERE CustomerID = 3
Comparison Operators
Copy Code
Type Operators
Arithmetic operators +-div mod
General comparison operators = = lt gt lt= gt=
Value comparison operators eq ne lt gt le ge
Node comparison operator is
Node order comparison operators gtgt ltlt
Logical operators and or
Copy Code
SQL Server 2005 has implemented support for four types of comparison operatorsmdashgeneral comparison operators valuecomparison operators node comparison operators and node order comparison operators
General comparison operators
General comparison operators help compare atomic values sequences or a combination of the two General comparisonoperators are = = lt gt lt= and gt= A general comparison is existentially quantified meaning that any match willresult in true
Example Selecting all address elements where the address type is not set to Home
The following query selects all Address nodes where the type of address is not set to Home and the JobCandidateID is3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $ARESAddrType[=Home]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Value comparison operators
Value comparison operators help compare atomic values Value comparison operators supported by SQL Server 2005 areeq ne lt gt le and ge The current implementation of XQuery with respect to promoting untyped atomic values is notaligned with the July 2004 draft of the XQuery specification The untyped atomic type is promoted to the type of the otheroperand instead of xsstring as specified in the XQuery specification This is to maintain consistency across general andvalue comparison operators which we consider more important than making the value comparison transitive
Example Selecting all education elements where the GPA is greater than 35
The following query selects all Education nodes where the GPA is greater than 35 for the candidate whoseJobCandidateID is 2
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal($EDRESEduGPA) gt 35return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Node comparison operators
You can use the node comparison operator is to compare two nodes to determine if they represent the same node or notThe node comparison operator accepts two operands that are of type node
Example Comparing two address nodes to check their identity
The following query compares two address nodes to check if they represent the same node in the document
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] is (RESAddress)[1] )then
ltResultgtNodes are equalltResultgtelse
ltResultgtNodes are not equalltResultgt) as ResultFROM [HumanResources][JobCandidate]
Copy Code
Copy Code
Copy Code
WHERE JobCandidateID = 3
Node order comparison operators
You can use the node order comparison operators to ascertain the order of two nodes in a document The node ordercomparison operators supported by SQL Sever 2005 are gtgt and ltlt and both the operators accept two operands The gtgtoperator returns true if the left operand precedes the right operand in document order and the ltlt operator returns trueif the left operand follows the right operand in document order
Example Comparing the order of two address nodes
The following query compares the order of two address nodes for a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddressRESAddrType[=Home])[1] ltlt
(RESResumeRESAddressRESAddrType[=Permanent])[1] )then
ltResultgtHome address precedes Permanent addressltResultgtelse
ltResultgtHome address follows Permanent addressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Logical Operators
The logical operators supported by XQuery in SQL Server 2005 are and and or The value of any logical expressionformed using these operators can be either true or false
Example Using the and operator to create a logical expression
The following query returns the candidates education element that contains bachelor level business degree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[RESEduLevel=Bachelor and RESEduMajor=Business]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
The if-then-else Construct
Like other functional languages XQuery supports the if-then-else construct You can use the if-then-else statement toperform operations based on the value of a conditional expression
Example Using a conditional expression
The following query displays the type of address that is specified in the resume for a candidate whose JobCandidateID is3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddressreturn
if ( $ARESAddrType eq Home )then
ltResultgtHome AddressltResultgtelse
ltResultgtOther AddressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Copy Code
Copy Code
Copy Code
Constructing XML Using XQuery
XQuery constructors enable you to create XML structures within a query Constructors are available for elementsattributes processing instructions text nodes and comments
The following examples illustrate these approaches to constructing XML
Example Using constant expressions
The following query displays employment history details constructed using constant expressions
SELECT Resumequery(ltEmployer IndustryCategory=ITServicesgtltOrganizationgtABC TechnologiesltOrganizationgtltJobTitlegtSoftware EngineerltJobTitlegtltStartDategt2001-10-01ltStartDategtltEndDategt2003-05-09ltEndDategt
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]
WHERE JobCandidateID = 3
Example Using data obtained dynamically
The following query displays employment history details constructed using the results obtained from a query for acandidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmployer Organization = $EMPRESEmpOrgName gt $EMPRESEmpStartDate $EMPRESEmpEndDate $EMPRESEmpJobTitle
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using constant names for computed element and attribute constructors
The following query displays the employment history of a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
element Employerattribute Organization $EMPRESEmpOrgName element StartDate string($EMPRESEmpStartDate) element EndDate string($EMPRESEmpEndDate) element JobTitle string($EMPRESEmpJobTitle)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Performing XQuery Construction vs Shaping Using FOR XML
Some applications have a requirement to generate XML from a rowset On the server XML can be generated using a FORXML clause or XQuery constructions or XML DML operations Recommendations on using FOR XML and XQueryconstructors for constructing XML are as follows
Copy Code
Copy Code
Copy Code
l If XML is to be aggregated from multiple columns and multiple rows then FOR XML is the only choice
l If a single XML instance is to be reshaped then it can be done using XQuery as well as FOR XML XQuery might befaster since the FOR XML approach will require multiple invocations of XML data type methods on the XML instance
l You can use multiple XML DML statements to construct an XML instance This approach is significantly slower thanXQuery construction
l Use the new TYPE directive available with the FOR XML clause in SQL Server 2005 to generate the result of a FORXML query as an instance of XML data type
Built-in XQuery Functions
Implementation of XQuery in SQL Server 2005 supports a subset of the built-in functions of XQuery 10 and XPath 20These functions include data accessor functions string manipulation functions aggregate functions context functionsnumeric functions Boolean functions node functions and sequence functions The following sections explore some ofthese functions
Data Accessors
You can use the data accessor functions to extract values of nodes as strings or typed values XQuery supports two typesof data accessor functions string() which extracts the string value of an item and data() which gets the typed value Ifthe node is not a text node an attribute node or an element node then the data() function throws a static error If thenode is a document node of an untyped XML instance then data() returns a string value of the document The data()function returns a static error if the node is a complex typed element
Example Using the string() function
See the Using constant names for computed element and attribute constructors example in the section Constructing XMLUsing XQuery in this paper for a query that generates the employment history of a candidate by using the string()function and computed element constructors
Example Using the data() function
The following query generates the employment history of a candidate by using the data() function and computed elementconstructors
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) gt 35return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
String Manipulation
XQuery supports four string manipulation functions
l concat() Helps concatenate two or more strings
l contains() Helps determine whether or not a string specified as the first operand contains another string specifiedas the second operand The length of the search string is limited to 4000 Unicode characters
l substring() Helps extract portion of a string from another string known as source string
l string-length() Helps calculate the length of a string
The current release of SQL Server 2005 supports only the Unicode codepoint collation
Example Using the concat() and substring() functions
The following query generates the employment history of a candidate by concatenating the values of start date enddate organization name and job title
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmploymentgtconcat( substring(string($EMPRESEmpStartDate)110) to
substring(string($EMPRESEmpEndDate)110) string($EMPRESEmpOrgName) string($EMPRESEmpJobTitle) )
ltEmploymentgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the contains() function
The following query demonstrates the use of the contains() function by displaying Education details for a node thatcontains the string science in the value of the element EduDegree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere contains($EDRESEduDegree Science)return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Aggregate Functions
Aggregate functions operate on a sequence of items and return the aggregate values of the sequence Aggregate functionscurrently supported in the XQuery support in SQL Server 2005 are count() min() max() avg() and sum() Thefunctions min() and max() accept only base types that support the gt operator (ie the three built-in numeric basetypes the datetime base types xsstring xsboolean and xdtuntypedAtomic) A sequence of mixed types is notsupported in these functions Furthermore xdtuntypedAtomic is treated as xsdouble
For avg() and sum() the type of the passed expression needs to be a subtype of one of the three built-in numeric basetypes or untypedAtomic (but not a mixture xdtuntypedAtomic is treated as xsdouble)
The count() function returns the number of items in a sequence
Example Using the count() function
The following query displays the count of employment education and address elements present in the documentusing the count() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeltEmploymentgtElement count is count(RESResumeRESAddress) ltEmploymentgtltEducationgtElement count is count(RESResumeRESEducation) ltEducationgtltAddressgtElement count is count(RESResumeRESAddress) ltAddressgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the min() function
The following query displays the education element for which the GPA value is minimum using the min() function
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = min(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the max() function
The following query displays the education element for which the GPA value is maximum using the max() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = max(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the avg() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using theavg() function
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt avg(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoNewYorkTempLow) ltAvgLowgt
ltNewYorkgtltBostongt
ltAvgHighgt avg(WeatherInfoBostonTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Example Using the sum() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using the
Copy Code
Copy Code
Copy Code
sum() and count() functions
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt sum(WeatherInfoNewYorkTempHigh) div count
(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt sum(WeatherInfoNewYorkTempLow) div count
(WeatherInfoNewYorkTempLow) ltAvgLowgtltNewYorkgtltBostongt
ltAvgHighgt sum(WeatherInfoBostonTempHigh) div count(WeatherInfoBostonTempHigh) ltAvgHighgt
ltAvgLowgt sum(WeatherInfoBostonTempLow) div count(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Context Functions
You can use the context functions to obtain the contextual properties of a context item SQL Server 2005 implements twocontext functionsmdashlast() and position() The last() function can be used to determine the number of items in asequence and the position() function can be used to obtain the position of a context item Both the last() and position() functions without an argument can only be used in the context of a context-dependent predicate (ie inside []) in SQLServer 2005
Example Using the last() function
The following query retrieves the last address element for a candidate using the last() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[last()]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the position() function
The following query retrieves the first two address elements for a candidate using the position() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[position()lt=2]
) as Result
Copy Code
Copy Code
Copy Code
FROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type-Related Expressions
XQuery supports various types of expressions or operators that are based on the type information These expressions canbe classified as type assertion expressions type inspection expressions and type casting expressions These expressionsare discussed briefly in the following sections
Type Assertion Expressions
as xsTYPE clause in for statement
You can use the as clause to specify the type for the binding variable used in the for statement
When a type is declared for the binding variable binding values that are not of the declared type would result in typeerror The xsTYPE clause is not a cast expression but it serves as a type assertion
Example Using as xsTYPE clause with for statement
The following query binds the address node sequence to a variable $A which is defined as type element(RESAddress)
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A as element(RESAddress) in RESResumeRESAddressreturn
$A) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Type Inspection Expressions
instance of xsTYPE operator
The instance of operator helps identify the runtime type of an item in an XML document
Example Using instance of xsTYPE operator
The following query checks to see if the type of an address node identified by an XPath expression matches element() typeor not
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] instance of element() )then
ltResultgtSelected node is an ElementltResultgtelse
ltResultgtSelected node is not an ElementltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type Casting Expressions
Implicit Type Casting
The XQuery engine performs implicit type casting for numeric types and untypedAtomic values in expressions that containarithmetic operations or function invocations This process is known as type promotion Type promotion occurs when anexpression results in a numeric type that is incompatible with the expected numeric type Type promotion is performed bycasting the resulting expression to the required type
Example Implicit type casting
The following query performs an arithmetic operation on a decimal value and a double value In the current scenario the
Copy Code
Copy Code
values in the expression are added only after promoting the xsdecimal value to xsdouble
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(
ltResultgt xsdecimal(1055) + xsdouble(15e1) ltResultgt) as Result
Explicit Type Casting
Typed value constructors
XQuery provides constructor functions for all built-in types defined in the XML Schema specification These constructorsare useful for constructing typed values and also for casting values from one type to another XQuery also makesconstructors available for types that are defined in imported schemas
Example Using a value constructor for constructing values
The following query returns all Employment nodes for which the StartDate is greater than a value constructed usingconstructor for type xsdate
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentwhere $EMPRESEmpStartDate gt xsdate(1995-01-01)return
$EMP) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using a value constructor for typecasting
The following query selects all Education nodes where the GPA is greater than or equal to 38 for the candidate whoseJobCandidateID is 2 This query uses the value constructor for xsdecimal for typecasting the value of EduGPA fromxsstring to xsdecimal
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) ge 38return
element Educationelement Level string($EDRESEduLevel)element StartDate string($EDRESEduStartDate)element EndDate string($EDRESEduEndDate)element Degree string($EDRESEduDegree)element GPA string($EDRESEduGPA)element GPAScale string($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
cast as xsTYPE Operator
XQuery in SQL Server 2005 supports the cast as TYPE operator which is useful for performing explicit type castingExplicit type casting can also be performed using the xsTYPE() constructors which are more convenient to write thanthe cast as TYPE operator
Example Using cast as xsTYPE operator
The following query generates an XML that contains typed values of selected elements from Education node set for acandidate whose JobCandidateID is 3
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level $EDRESEduLevel cast as xsstring element StartDate $EDRESEduStartDate cast as xsdate element EndDate $EDRESEduEndDate cast as xsdate element Degree $EDRESEduDegree cast as xsstring element GPA $EDRESEduGPA cast as xsdecimal element GPAScale $EDRESEduGPAScale cast as xsdecimal
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using xsTYPE() operator
The following query generates the same results as the query in the previous example using the xsTYPE() operatorinstead of the cast as xsTYPE operator
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level xsstring($EDRESEduLevel) element StartDate xsdate($EDRESEduStartDate) element EndDate xsdate($EDRESEduEndDate) element Degree xsstring($EDRESEduDegree) element GPA xsdecimal($EDRESEduGPA) element GPAScale xsdecimal($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Accessing Relational Columns and Variables
When writing queries using XQuery it is not uncommon to have the requirement for accessing relational columns andvariables from within the query SQL Server 2005 caters to this requirement by implementing two functionsmdashsqlcolumn() and sqlvariable()
The function sqlcolumn() can be used to access non-XML columns in a relational table from within a query This functionis useful for scenarios such as aggregating information from XML and non-XML type columns of one or more tables usingthe values of non-XML columns to filter the results of an XQuery and so on The functions sqlcolumn() andsqlvariable() cannot be used with datetime CLR user-defined functions or XML
Example Using sqlcolumn() function
The following query generates an XML that contains values from the CustomerID and Name columns of non-XML datatype and values of YearOpened NumberOfEmployees AnnualSales and AnnualRevenue elements from theDemographics column
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyelement CustomerInfo
element CustomerID sqlcolumn(StoreCustomerID) element Name sqlcolumn(StoreName) element YearOpened string((STStoreSurveySTYearOpened)[1]) element NumberOfEmployees string((STStoreSurveySTNumberEmployees)[1]) element AnnualSales string((STStoreSurveySTAnnualSales)[1]) element AnnualRevenue string((STStoreSurveySTAnnualRevenue)[1])
) as Result
Copy Code
Copy Code
Copy Code
FROM [Sales][Store] StoreWHERE StoreCustomerID = 4
Example Using sqlvariable() function
The following stored procedure returns home address nodes of a specified candidate by using the value of theAddrType variable in the XQuery where clause to filter the results of the query
CREATE PROCEDURE [GetCandidateAddress]JobCandidateID [int]AddrType [varchar](20)
ASBEGIN
SET NOCOUNT ON
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $A[ RESAddrType = sqlvariable(AddrType) ]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = JobCandidateID
END
Example Using sqlvariable() function in conjunction with the exist() method of the XML data type
The following query returns resumes of candidates who hold a Bachelors degree with a major in Business
DECLARE EducationLevel varchar(20)SET EducationLevel = Bachelor
DECLARE Major varchar(20)SET Major = Business
SELECT JobCandidateID ResumeFROM [HumanResources][JobCandidate]WHERE Resumeexist (
declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[ RESEduLevel = sqlvariable(EducationLevel) and RESEduMajor
= sqlvariable(Major) ]) = 1
Non-Supported Features and Workarounds
Current implementation of XQuery in SQL Server 2005 does not support the following features
l The let clause The let clause which is a part of the FLWOR expression is useful for binding a variable to the resultsof an expression WorkaroundmdashInstead of using the let clause use an inline expression
l Range expression (to operator) A range expression can be used to construct a sequence of consecutive integersusing the to operator For example using a range expression such as (6 to 10) it is possible to construct thesequence (6 7 8 9 10) WorkaroundmdashInstead of using the to operator list all items in your sequence
l Type information Some features that are based on type system such as typeswitch treat as castable andvalidate expressions are currently not supported
l The functionality of a typeswitch expression is similar to the switch-case construct available in otherprogramming languages In a switch-case statement the branchescases are selected based on the value of theargument passed to the switch In a typeswitch expression the branches are selected based on the type of theargument passed to typeswitch Workaroundmdashuse if then else and instance of
l The treat as expression can be used to change the static type of the result of an expression to a specific statictype and raises a static type error if the static type of the expression does not match the specified type It doesnot change the dynamic type or value of the expression Workaroundmdashnone
l The castable expression is useful for checking whether an atomic value can be cast to the specified typeWorkaroundmdashInstead of using the expression $x castable as T use the expression empty(data($x)) or not(empty(T($x)))
Copy Code
Copy Code
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
l ns is the namespace prefix
l AddrType is the node test
l [=Home] is the predicate expression where refers to the context node
XQuery also supports abbreviated syntax for specifying the axis The following table shows the axis and correspondingabbreviated syntax
Table 2 Abbreviated syntax for axes
Example Selecting organization names from employment history
The following XPath expression selects the children text nodes of EmpOrgName elements that are child nodes of nodeResumeEmployment Here text() is used to select the text node of the EmpOrgName element
ResumeEmploymentEmpOrgNametext()
The FLWOR Statement
FLWOR statements form the core expressions of XQuery and are similar to the SELECT statements of SQL The acronymFLWOR (pronounced flower) stands for FOR LET WHERE ORDER BY RETURN FLWOR expressions in XQuery enableusers to specify operations such as declarative iteration variable binding filtering sorting and returning the results SQLServer 2005 supports FOR WHERE ORDER BY and RETURN
For
The for clause in a FLWOR expression enables users to define a declarative iteration of a bound variable over an inputsequence The input sequence can be specified using XPath expressions sequence of atomic values a sequenceconstructed using literals or constructor functions It is therefore analogous to the SQL SELECT FROM clause and is notlike a programming language for construct
Variable binding is also specified in the for clause
Example Selecting all home address elements from resume using the for clause
The following query selects all Address nodes where the type of address is set to Home and the JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddressRESAddrType[=Home]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
where
The where clause filters the results of an iteration by applying the expression specified with the where clause
Example Selecting all home address elements using the where clause
The following query selects all Address nodes where the type of address is set to Home and the JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $ARESAddrType[=Home]
Axis Abbreviated form
Attribute
Child
descendant-or-selfnode()
parentnode()
selfnode()
Copy Code
Copy Code
return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
order by
The order by keyword enables you to sort the values in the returned result set The order by keyword accepts a sortingexpression which should return an atomic value Optionally you can also specify ascending or descending for the sortorder The default sort order is ascending
Example Selecting employment history in ascending order using the order by clause
The following query selects all Employment nodes in ascending order of employment starting date for a candidate whoseJobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentorder by $EMPRESEmpStartDatereturn$EMP
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
return
The return clause which is analogous to the SELECT clause in SQL enables users to define the result of a query You canspecify any valid XQuery expression in the return clause You can also construct XML structures in the return section byspecifying constructors for elements attributes etc
Example Selecting specific elements of employment history using the return clause
The following query selects StartDate EndDate OrgName JobTitle elements of Employment node for a candidate whoseJobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentorder by $EMPRESEmpStartDatereturn
ltEmploymentgt $EMPRESEmpStartDate $EMPRESEmpEndDate $EMPRESEmpOrgName $EMPRESEmpJobTitle
ltEmploymentgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Current implementation of XQuery in SQL Server 2005 does not support the let clause This aspect is discussed further inNon-supported Features and Workarounds in this paper
FLWOR Expressions vs XPath Expressions
Using a FLWOR expression to define the result sequence when the sequence can be expressed using an XPath expressionincurs a performance penalty because the query plan contains a JOIN operation between the for variable and the body ofthe for clause The use of a FLWOR expression is justified only if one or more of the following conditions are satisfied
l If you want to iterate over a sequence of values that are returned as a result of an expression This is achieved usingthe for clause which binds a variable to successive values of the result set Examples are the construction of newelements within the scope of the for clause and the retention of duplicates
l When you want to filter the result sequence of the for clause based on a predicate which cannot be defined using
Copy Code
Copy Code
simple XPath expressions The where clause is used to eliminate unwanted values in the result set An example is asfollows
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(for $i in (1 2 3) $j in (3 4 5)where $i lt $jreturn sum($i + $j)) as Result
l If you want to sort the result set based on a sorting expression Sorting is defined on the result set using the orderby clause
l When you want to define the shape of the returned result set using the results obtained from the for clause Thereturn statement is used to perform the shaping of the result set
In all other cases using XPath expressions is recommended
Operators in XQuery
As a functional language XQuery in SQL Server 2005 supports various types of functions and operators that can begrouped under the following categories
l Arithmetic operators
l Comparison operators
l Logical operators
Table 3 Operators supported in SQL Server 2005
Arithmetic Operators
SQL Server 2005 supports five arithmetic operators These are + b div and mod Currently it does not support idiv
Example Converting selected values of store survey information
This example is based on the [Sales][Store] table in the AdventureWorks database The following query returns values ofAnnualSales AnnualRevenue in yen and the store area in square meters for a store whose CustomerID is 3
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyfor $S in STStoreSurveyreturn
ltStoreDetailsSalesInYen = $SSTAnnualSales1068100 RevenueInYen = $SSTAnnualRevenue1068100 StoreAreaInSqMeters = $SSTSquareFeet00929 gt
ltStoreDetailsgt) as ResultFROM [Sales][Store]WHERE CustomerID = 3
Comparison Operators
Copy Code
Type Operators
Arithmetic operators +-div mod
General comparison operators = = lt gt lt= gt=
Value comparison operators eq ne lt gt le ge
Node comparison operator is
Node order comparison operators gtgt ltlt
Logical operators and or
Copy Code
SQL Server 2005 has implemented support for four types of comparison operatorsmdashgeneral comparison operators valuecomparison operators node comparison operators and node order comparison operators
General comparison operators
General comparison operators help compare atomic values sequences or a combination of the two General comparisonoperators are = = lt gt lt= and gt= A general comparison is existentially quantified meaning that any match willresult in true
Example Selecting all address elements where the address type is not set to Home
The following query selects all Address nodes where the type of address is not set to Home and the JobCandidateID is3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $ARESAddrType[=Home]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Value comparison operators
Value comparison operators help compare atomic values Value comparison operators supported by SQL Server 2005 areeq ne lt gt le and ge The current implementation of XQuery with respect to promoting untyped atomic values is notaligned with the July 2004 draft of the XQuery specification The untyped atomic type is promoted to the type of the otheroperand instead of xsstring as specified in the XQuery specification This is to maintain consistency across general andvalue comparison operators which we consider more important than making the value comparison transitive
Example Selecting all education elements where the GPA is greater than 35
The following query selects all Education nodes where the GPA is greater than 35 for the candidate whoseJobCandidateID is 2
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal($EDRESEduGPA) gt 35return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Node comparison operators
You can use the node comparison operator is to compare two nodes to determine if they represent the same node or notThe node comparison operator accepts two operands that are of type node
Example Comparing two address nodes to check their identity
The following query compares two address nodes to check if they represent the same node in the document
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] is (RESAddress)[1] )then
ltResultgtNodes are equalltResultgtelse
ltResultgtNodes are not equalltResultgt) as ResultFROM [HumanResources][JobCandidate]
Copy Code
Copy Code
Copy Code
WHERE JobCandidateID = 3
Node order comparison operators
You can use the node order comparison operators to ascertain the order of two nodes in a document The node ordercomparison operators supported by SQL Sever 2005 are gtgt and ltlt and both the operators accept two operands The gtgtoperator returns true if the left operand precedes the right operand in document order and the ltlt operator returns trueif the left operand follows the right operand in document order
Example Comparing the order of two address nodes
The following query compares the order of two address nodes for a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddressRESAddrType[=Home])[1] ltlt
(RESResumeRESAddressRESAddrType[=Permanent])[1] )then
ltResultgtHome address precedes Permanent addressltResultgtelse
ltResultgtHome address follows Permanent addressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Logical Operators
The logical operators supported by XQuery in SQL Server 2005 are and and or The value of any logical expressionformed using these operators can be either true or false
Example Using the and operator to create a logical expression
The following query returns the candidates education element that contains bachelor level business degree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[RESEduLevel=Bachelor and RESEduMajor=Business]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
The if-then-else Construct
Like other functional languages XQuery supports the if-then-else construct You can use the if-then-else statement toperform operations based on the value of a conditional expression
Example Using a conditional expression
The following query displays the type of address that is specified in the resume for a candidate whose JobCandidateID is3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddressreturn
if ( $ARESAddrType eq Home )then
ltResultgtHome AddressltResultgtelse
ltResultgtOther AddressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Copy Code
Copy Code
Copy Code
Constructing XML Using XQuery
XQuery constructors enable you to create XML structures within a query Constructors are available for elementsattributes processing instructions text nodes and comments
The following examples illustrate these approaches to constructing XML
Example Using constant expressions
The following query displays employment history details constructed using constant expressions
SELECT Resumequery(ltEmployer IndustryCategory=ITServicesgtltOrganizationgtABC TechnologiesltOrganizationgtltJobTitlegtSoftware EngineerltJobTitlegtltStartDategt2001-10-01ltStartDategtltEndDategt2003-05-09ltEndDategt
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]
WHERE JobCandidateID = 3
Example Using data obtained dynamically
The following query displays employment history details constructed using the results obtained from a query for acandidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmployer Organization = $EMPRESEmpOrgName gt $EMPRESEmpStartDate $EMPRESEmpEndDate $EMPRESEmpJobTitle
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using constant names for computed element and attribute constructors
The following query displays the employment history of a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
element Employerattribute Organization $EMPRESEmpOrgName element StartDate string($EMPRESEmpStartDate) element EndDate string($EMPRESEmpEndDate) element JobTitle string($EMPRESEmpJobTitle)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Performing XQuery Construction vs Shaping Using FOR XML
Some applications have a requirement to generate XML from a rowset On the server XML can be generated using a FORXML clause or XQuery constructions or XML DML operations Recommendations on using FOR XML and XQueryconstructors for constructing XML are as follows
Copy Code
Copy Code
Copy Code
l If XML is to be aggregated from multiple columns and multiple rows then FOR XML is the only choice
l If a single XML instance is to be reshaped then it can be done using XQuery as well as FOR XML XQuery might befaster since the FOR XML approach will require multiple invocations of XML data type methods on the XML instance
l You can use multiple XML DML statements to construct an XML instance This approach is significantly slower thanXQuery construction
l Use the new TYPE directive available with the FOR XML clause in SQL Server 2005 to generate the result of a FORXML query as an instance of XML data type
Built-in XQuery Functions
Implementation of XQuery in SQL Server 2005 supports a subset of the built-in functions of XQuery 10 and XPath 20These functions include data accessor functions string manipulation functions aggregate functions context functionsnumeric functions Boolean functions node functions and sequence functions The following sections explore some ofthese functions
Data Accessors
You can use the data accessor functions to extract values of nodes as strings or typed values XQuery supports two typesof data accessor functions string() which extracts the string value of an item and data() which gets the typed value Ifthe node is not a text node an attribute node or an element node then the data() function throws a static error If thenode is a document node of an untyped XML instance then data() returns a string value of the document The data()function returns a static error if the node is a complex typed element
Example Using the string() function
See the Using constant names for computed element and attribute constructors example in the section Constructing XMLUsing XQuery in this paper for a query that generates the employment history of a candidate by using the string()function and computed element constructors
Example Using the data() function
The following query generates the employment history of a candidate by using the data() function and computed elementconstructors
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) gt 35return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
String Manipulation
XQuery supports four string manipulation functions
l concat() Helps concatenate two or more strings
l contains() Helps determine whether or not a string specified as the first operand contains another string specifiedas the second operand The length of the search string is limited to 4000 Unicode characters
l substring() Helps extract portion of a string from another string known as source string
l string-length() Helps calculate the length of a string
The current release of SQL Server 2005 supports only the Unicode codepoint collation
Example Using the concat() and substring() functions
The following query generates the employment history of a candidate by concatenating the values of start date enddate organization name and job title
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmploymentgtconcat( substring(string($EMPRESEmpStartDate)110) to
substring(string($EMPRESEmpEndDate)110) string($EMPRESEmpOrgName) string($EMPRESEmpJobTitle) )
ltEmploymentgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the contains() function
The following query demonstrates the use of the contains() function by displaying Education details for a node thatcontains the string science in the value of the element EduDegree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere contains($EDRESEduDegree Science)return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Aggregate Functions
Aggregate functions operate on a sequence of items and return the aggregate values of the sequence Aggregate functionscurrently supported in the XQuery support in SQL Server 2005 are count() min() max() avg() and sum() Thefunctions min() and max() accept only base types that support the gt operator (ie the three built-in numeric basetypes the datetime base types xsstring xsboolean and xdtuntypedAtomic) A sequence of mixed types is notsupported in these functions Furthermore xdtuntypedAtomic is treated as xsdouble
For avg() and sum() the type of the passed expression needs to be a subtype of one of the three built-in numeric basetypes or untypedAtomic (but not a mixture xdtuntypedAtomic is treated as xsdouble)
The count() function returns the number of items in a sequence
Example Using the count() function
The following query displays the count of employment education and address elements present in the documentusing the count() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeltEmploymentgtElement count is count(RESResumeRESAddress) ltEmploymentgtltEducationgtElement count is count(RESResumeRESEducation) ltEducationgtltAddressgtElement count is count(RESResumeRESAddress) ltAddressgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the min() function
The following query displays the education element for which the GPA value is minimum using the min() function
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = min(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the max() function
The following query displays the education element for which the GPA value is maximum using the max() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = max(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the avg() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using theavg() function
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt avg(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoNewYorkTempLow) ltAvgLowgt
ltNewYorkgtltBostongt
ltAvgHighgt avg(WeatherInfoBostonTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Example Using the sum() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using the
Copy Code
Copy Code
Copy Code
sum() and count() functions
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt sum(WeatherInfoNewYorkTempHigh) div count
(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt sum(WeatherInfoNewYorkTempLow) div count
(WeatherInfoNewYorkTempLow) ltAvgLowgtltNewYorkgtltBostongt
ltAvgHighgt sum(WeatherInfoBostonTempHigh) div count(WeatherInfoBostonTempHigh) ltAvgHighgt
ltAvgLowgt sum(WeatherInfoBostonTempLow) div count(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Context Functions
You can use the context functions to obtain the contextual properties of a context item SQL Server 2005 implements twocontext functionsmdashlast() and position() The last() function can be used to determine the number of items in asequence and the position() function can be used to obtain the position of a context item Both the last() and position() functions without an argument can only be used in the context of a context-dependent predicate (ie inside []) in SQLServer 2005
Example Using the last() function
The following query retrieves the last address element for a candidate using the last() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[last()]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the position() function
The following query retrieves the first two address elements for a candidate using the position() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[position()lt=2]
) as Result
Copy Code
Copy Code
Copy Code
FROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type-Related Expressions
XQuery supports various types of expressions or operators that are based on the type information These expressions canbe classified as type assertion expressions type inspection expressions and type casting expressions These expressionsare discussed briefly in the following sections
Type Assertion Expressions
as xsTYPE clause in for statement
You can use the as clause to specify the type for the binding variable used in the for statement
When a type is declared for the binding variable binding values that are not of the declared type would result in typeerror The xsTYPE clause is not a cast expression but it serves as a type assertion
Example Using as xsTYPE clause with for statement
The following query binds the address node sequence to a variable $A which is defined as type element(RESAddress)
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A as element(RESAddress) in RESResumeRESAddressreturn
$A) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Type Inspection Expressions
instance of xsTYPE operator
The instance of operator helps identify the runtime type of an item in an XML document
Example Using instance of xsTYPE operator
The following query checks to see if the type of an address node identified by an XPath expression matches element() typeor not
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] instance of element() )then
ltResultgtSelected node is an ElementltResultgtelse
ltResultgtSelected node is not an ElementltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type Casting Expressions
Implicit Type Casting
The XQuery engine performs implicit type casting for numeric types and untypedAtomic values in expressions that containarithmetic operations or function invocations This process is known as type promotion Type promotion occurs when anexpression results in a numeric type that is incompatible with the expected numeric type Type promotion is performed bycasting the resulting expression to the required type
Example Implicit type casting
The following query performs an arithmetic operation on a decimal value and a double value In the current scenario the
Copy Code
Copy Code
values in the expression are added only after promoting the xsdecimal value to xsdouble
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(
ltResultgt xsdecimal(1055) + xsdouble(15e1) ltResultgt) as Result
Explicit Type Casting
Typed value constructors
XQuery provides constructor functions for all built-in types defined in the XML Schema specification These constructorsare useful for constructing typed values and also for casting values from one type to another XQuery also makesconstructors available for types that are defined in imported schemas
Example Using a value constructor for constructing values
The following query returns all Employment nodes for which the StartDate is greater than a value constructed usingconstructor for type xsdate
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentwhere $EMPRESEmpStartDate gt xsdate(1995-01-01)return
$EMP) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using a value constructor for typecasting
The following query selects all Education nodes where the GPA is greater than or equal to 38 for the candidate whoseJobCandidateID is 2 This query uses the value constructor for xsdecimal for typecasting the value of EduGPA fromxsstring to xsdecimal
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) ge 38return
element Educationelement Level string($EDRESEduLevel)element StartDate string($EDRESEduStartDate)element EndDate string($EDRESEduEndDate)element Degree string($EDRESEduDegree)element GPA string($EDRESEduGPA)element GPAScale string($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
cast as xsTYPE Operator
XQuery in SQL Server 2005 supports the cast as TYPE operator which is useful for performing explicit type castingExplicit type casting can also be performed using the xsTYPE() constructors which are more convenient to write thanthe cast as TYPE operator
Example Using cast as xsTYPE operator
The following query generates an XML that contains typed values of selected elements from Education node set for acandidate whose JobCandidateID is 3
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level $EDRESEduLevel cast as xsstring element StartDate $EDRESEduStartDate cast as xsdate element EndDate $EDRESEduEndDate cast as xsdate element Degree $EDRESEduDegree cast as xsstring element GPA $EDRESEduGPA cast as xsdecimal element GPAScale $EDRESEduGPAScale cast as xsdecimal
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using xsTYPE() operator
The following query generates the same results as the query in the previous example using the xsTYPE() operatorinstead of the cast as xsTYPE operator
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level xsstring($EDRESEduLevel) element StartDate xsdate($EDRESEduStartDate) element EndDate xsdate($EDRESEduEndDate) element Degree xsstring($EDRESEduDegree) element GPA xsdecimal($EDRESEduGPA) element GPAScale xsdecimal($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Accessing Relational Columns and Variables
When writing queries using XQuery it is not uncommon to have the requirement for accessing relational columns andvariables from within the query SQL Server 2005 caters to this requirement by implementing two functionsmdashsqlcolumn() and sqlvariable()
The function sqlcolumn() can be used to access non-XML columns in a relational table from within a query This functionis useful for scenarios such as aggregating information from XML and non-XML type columns of one or more tables usingthe values of non-XML columns to filter the results of an XQuery and so on The functions sqlcolumn() andsqlvariable() cannot be used with datetime CLR user-defined functions or XML
Example Using sqlcolumn() function
The following query generates an XML that contains values from the CustomerID and Name columns of non-XML datatype and values of YearOpened NumberOfEmployees AnnualSales and AnnualRevenue elements from theDemographics column
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyelement CustomerInfo
element CustomerID sqlcolumn(StoreCustomerID) element Name sqlcolumn(StoreName) element YearOpened string((STStoreSurveySTYearOpened)[1]) element NumberOfEmployees string((STStoreSurveySTNumberEmployees)[1]) element AnnualSales string((STStoreSurveySTAnnualSales)[1]) element AnnualRevenue string((STStoreSurveySTAnnualRevenue)[1])
) as Result
Copy Code
Copy Code
Copy Code
FROM [Sales][Store] StoreWHERE StoreCustomerID = 4
Example Using sqlvariable() function
The following stored procedure returns home address nodes of a specified candidate by using the value of theAddrType variable in the XQuery where clause to filter the results of the query
CREATE PROCEDURE [GetCandidateAddress]JobCandidateID [int]AddrType [varchar](20)
ASBEGIN
SET NOCOUNT ON
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $A[ RESAddrType = sqlvariable(AddrType) ]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = JobCandidateID
END
Example Using sqlvariable() function in conjunction with the exist() method of the XML data type
The following query returns resumes of candidates who hold a Bachelors degree with a major in Business
DECLARE EducationLevel varchar(20)SET EducationLevel = Bachelor
DECLARE Major varchar(20)SET Major = Business
SELECT JobCandidateID ResumeFROM [HumanResources][JobCandidate]WHERE Resumeexist (
declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[ RESEduLevel = sqlvariable(EducationLevel) and RESEduMajor
= sqlvariable(Major) ]) = 1
Non-Supported Features and Workarounds
Current implementation of XQuery in SQL Server 2005 does not support the following features
l The let clause The let clause which is a part of the FLWOR expression is useful for binding a variable to the resultsof an expression WorkaroundmdashInstead of using the let clause use an inline expression
l Range expression (to operator) A range expression can be used to construct a sequence of consecutive integersusing the to operator For example using a range expression such as (6 to 10) it is possible to construct thesequence (6 7 8 9 10) WorkaroundmdashInstead of using the to operator list all items in your sequence
l Type information Some features that are based on type system such as typeswitch treat as castable andvalidate expressions are currently not supported
l The functionality of a typeswitch expression is similar to the switch-case construct available in otherprogramming languages In a switch-case statement the branchescases are selected based on the value of theargument passed to the switch In a typeswitch expression the branches are selected based on the type of theargument passed to typeswitch Workaroundmdashuse if then else and instance of
l The treat as expression can be used to change the static type of the result of an expression to a specific statictype and raises a static type error if the static type of the expression does not match the specified type It doesnot change the dynamic type or value of the expression Workaroundmdashnone
l The castable expression is useful for checking whether an atomic value can be cast to the specified typeWorkaroundmdashInstead of using the expression $x castable as T use the expression empty(data($x)) or not(empty(T($x)))
Copy Code
Copy Code
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
order by
The order by keyword enables you to sort the values in the returned result set The order by keyword accepts a sortingexpression which should return an atomic value Optionally you can also specify ascending or descending for the sortorder The default sort order is ascending
Example Selecting employment history in ascending order using the order by clause
The following query selects all Employment nodes in ascending order of employment starting date for a candidate whoseJobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentorder by $EMPRESEmpStartDatereturn$EMP
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
return
The return clause which is analogous to the SELECT clause in SQL enables users to define the result of a query You canspecify any valid XQuery expression in the return clause You can also construct XML structures in the return section byspecifying constructors for elements attributes etc
Example Selecting specific elements of employment history using the return clause
The following query selects StartDate EndDate OrgName JobTitle elements of Employment node for a candidate whoseJobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentorder by $EMPRESEmpStartDatereturn
ltEmploymentgt $EMPRESEmpStartDate $EMPRESEmpEndDate $EMPRESEmpOrgName $EMPRESEmpJobTitle
ltEmploymentgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Current implementation of XQuery in SQL Server 2005 does not support the let clause This aspect is discussed further inNon-supported Features and Workarounds in this paper
FLWOR Expressions vs XPath Expressions
Using a FLWOR expression to define the result sequence when the sequence can be expressed using an XPath expressionincurs a performance penalty because the query plan contains a JOIN operation between the for variable and the body ofthe for clause The use of a FLWOR expression is justified only if one or more of the following conditions are satisfied
l If you want to iterate over a sequence of values that are returned as a result of an expression This is achieved usingthe for clause which binds a variable to successive values of the result set Examples are the construction of newelements within the scope of the for clause and the retention of duplicates
l When you want to filter the result sequence of the for clause based on a predicate which cannot be defined using
Copy Code
Copy Code
simple XPath expressions The where clause is used to eliminate unwanted values in the result set An example is asfollows
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(for $i in (1 2 3) $j in (3 4 5)where $i lt $jreturn sum($i + $j)) as Result
l If you want to sort the result set based on a sorting expression Sorting is defined on the result set using the orderby clause
l When you want to define the shape of the returned result set using the results obtained from the for clause Thereturn statement is used to perform the shaping of the result set
In all other cases using XPath expressions is recommended
Operators in XQuery
As a functional language XQuery in SQL Server 2005 supports various types of functions and operators that can begrouped under the following categories
l Arithmetic operators
l Comparison operators
l Logical operators
Table 3 Operators supported in SQL Server 2005
Arithmetic Operators
SQL Server 2005 supports five arithmetic operators These are + b div and mod Currently it does not support idiv
Example Converting selected values of store survey information
This example is based on the [Sales][Store] table in the AdventureWorks database The following query returns values ofAnnualSales AnnualRevenue in yen and the store area in square meters for a store whose CustomerID is 3
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyfor $S in STStoreSurveyreturn
ltStoreDetailsSalesInYen = $SSTAnnualSales1068100 RevenueInYen = $SSTAnnualRevenue1068100 StoreAreaInSqMeters = $SSTSquareFeet00929 gt
ltStoreDetailsgt) as ResultFROM [Sales][Store]WHERE CustomerID = 3
Comparison Operators
Copy Code
Type Operators
Arithmetic operators +-div mod
General comparison operators = = lt gt lt= gt=
Value comparison operators eq ne lt gt le ge
Node comparison operator is
Node order comparison operators gtgt ltlt
Logical operators and or
Copy Code
SQL Server 2005 has implemented support for four types of comparison operatorsmdashgeneral comparison operators valuecomparison operators node comparison operators and node order comparison operators
General comparison operators
General comparison operators help compare atomic values sequences or a combination of the two General comparisonoperators are = = lt gt lt= and gt= A general comparison is existentially quantified meaning that any match willresult in true
Example Selecting all address elements where the address type is not set to Home
The following query selects all Address nodes where the type of address is not set to Home and the JobCandidateID is3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $ARESAddrType[=Home]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Value comparison operators
Value comparison operators help compare atomic values Value comparison operators supported by SQL Server 2005 areeq ne lt gt le and ge The current implementation of XQuery with respect to promoting untyped atomic values is notaligned with the July 2004 draft of the XQuery specification The untyped atomic type is promoted to the type of the otheroperand instead of xsstring as specified in the XQuery specification This is to maintain consistency across general andvalue comparison operators which we consider more important than making the value comparison transitive
Example Selecting all education elements where the GPA is greater than 35
The following query selects all Education nodes where the GPA is greater than 35 for the candidate whoseJobCandidateID is 2
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal($EDRESEduGPA) gt 35return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Node comparison operators
You can use the node comparison operator is to compare two nodes to determine if they represent the same node or notThe node comparison operator accepts two operands that are of type node
Example Comparing two address nodes to check their identity
The following query compares two address nodes to check if they represent the same node in the document
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] is (RESAddress)[1] )then
ltResultgtNodes are equalltResultgtelse
ltResultgtNodes are not equalltResultgt) as ResultFROM [HumanResources][JobCandidate]
Copy Code
Copy Code
Copy Code
WHERE JobCandidateID = 3
Node order comparison operators
You can use the node order comparison operators to ascertain the order of two nodes in a document The node ordercomparison operators supported by SQL Sever 2005 are gtgt and ltlt and both the operators accept two operands The gtgtoperator returns true if the left operand precedes the right operand in document order and the ltlt operator returns trueif the left operand follows the right operand in document order
Example Comparing the order of two address nodes
The following query compares the order of two address nodes for a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddressRESAddrType[=Home])[1] ltlt
(RESResumeRESAddressRESAddrType[=Permanent])[1] )then
ltResultgtHome address precedes Permanent addressltResultgtelse
ltResultgtHome address follows Permanent addressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Logical Operators
The logical operators supported by XQuery in SQL Server 2005 are and and or The value of any logical expressionformed using these operators can be either true or false
Example Using the and operator to create a logical expression
The following query returns the candidates education element that contains bachelor level business degree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[RESEduLevel=Bachelor and RESEduMajor=Business]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
The if-then-else Construct
Like other functional languages XQuery supports the if-then-else construct You can use the if-then-else statement toperform operations based on the value of a conditional expression
Example Using a conditional expression
The following query displays the type of address that is specified in the resume for a candidate whose JobCandidateID is3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddressreturn
if ( $ARESAddrType eq Home )then
ltResultgtHome AddressltResultgtelse
ltResultgtOther AddressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Copy Code
Copy Code
Copy Code
Constructing XML Using XQuery
XQuery constructors enable you to create XML structures within a query Constructors are available for elementsattributes processing instructions text nodes and comments
The following examples illustrate these approaches to constructing XML
Example Using constant expressions
The following query displays employment history details constructed using constant expressions
SELECT Resumequery(ltEmployer IndustryCategory=ITServicesgtltOrganizationgtABC TechnologiesltOrganizationgtltJobTitlegtSoftware EngineerltJobTitlegtltStartDategt2001-10-01ltStartDategtltEndDategt2003-05-09ltEndDategt
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]
WHERE JobCandidateID = 3
Example Using data obtained dynamically
The following query displays employment history details constructed using the results obtained from a query for acandidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmployer Organization = $EMPRESEmpOrgName gt $EMPRESEmpStartDate $EMPRESEmpEndDate $EMPRESEmpJobTitle
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using constant names for computed element and attribute constructors
The following query displays the employment history of a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
element Employerattribute Organization $EMPRESEmpOrgName element StartDate string($EMPRESEmpStartDate) element EndDate string($EMPRESEmpEndDate) element JobTitle string($EMPRESEmpJobTitle)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Performing XQuery Construction vs Shaping Using FOR XML
Some applications have a requirement to generate XML from a rowset On the server XML can be generated using a FORXML clause or XQuery constructions or XML DML operations Recommendations on using FOR XML and XQueryconstructors for constructing XML are as follows
Copy Code
Copy Code
Copy Code
l If XML is to be aggregated from multiple columns and multiple rows then FOR XML is the only choice
l If a single XML instance is to be reshaped then it can be done using XQuery as well as FOR XML XQuery might befaster since the FOR XML approach will require multiple invocations of XML data type methods on the XML instance
l You can use multiple XML DML statements to construct an XML instance This approach is significantly slower thanXQuery construction
l Use the new TYPE directive available with the FOR XML clause in SQL Server 2005 to generate the result of a FORXML query as an instance of XML data type
Built-in XQuery Functions
Implementation of XQuery in SQL Server 2005 supports a subset of the built-in functions of XQuery 10 and XPath 20These functions include data accessor functions string manipulation functions aggregate functions context functionsnumeric functions Boolean functions node functions and sequence functions The following sections explore some ofthese functions
Data Accessors
You can use the data accessor functions to extract values of nodes as strings or typed values XQuery supports two typesof data accessor functions string() which extracts the string value of an item and data() which gets the typed value Ifthe node is not a text node an attribute node or an element node then the data() function throws a static error If thenode is a document node of an untyped XML instance then data() returns a string value of the document The data()function returns a static error if the node is a complex typed element
Example Using the string() function
See the Using constant names for computed element and attribute constructors example in the section Constructing XMLUsing XQuery in this paper for a query that generates the employment history of a candidate by using the string()function and computed element constructors
Example Using the data() function
The following query generates the employment history of a candidate by using the data() function and computed elementconstructors
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) gt 35return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
String Manipulation
XQuery supports four string manipulation functions
l concat() Helps concatenate two or more strings
l contains() Helps determine whether or not a string specified as the first operand contains another string specifiedas the second operand The length of the search string is limited to 4000 Unicode characters
l substring() Helps extract portion of a string from another string known as source string
l string-length() Helps calculate the length of a string
The current release of SQL Server 2005 supports only the Unicode codepoint collation
Example Using the concat() and substring() functions
The following query generates the employment history of a candidate by concatenating the values of start date enddate organization name and job title
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmploymentgtconcat( substring(string($EMPRESEmpStartDate)110) to
substring(string($EMPRESEmpEndDate)110) string($EMPRESEmpOrgName) string($EMPRESEmpJobTitle) )
ltEmploymentgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the contains() function
The following query demonstrates the use of the contains() function by displaying Education details for a node thatcontains the string science in the value of the element EduDegree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere contains($EDRESEduDegree Science)return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Aggregate Functions
Aggregate functions operate on a sequence of items and return the aggregate values of the sequence Aggregate functionscurrently supported in the XQuery support in SQL Server 2005 are count() min() max() avg() and sum() Thefunctions min() and max() accept only base types that support the gt operator (ie the three built-in numeric basetypes the datetime base types xsstring xsboolean and xdtuntypedAtomic) A sequence of mixed types is notsupported in these functions Furthermore xdtuntypedAtomic is treated as xsdouble
For avg() and sum() the type of the passed expression needs to be a subtype of one of the three built-in numeric basetypes or untypedAtomic (but not a mixture xdtuntypedAtomic is treated as xsdouble)
The count() function returns the number of items in a sequence
Example Using the count() function
The following query displays the count of employment education and address elements present in the documentusing the count() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeltEmploymentgtElement count is count(RESResumeRESAddress) ltEmploymentgtltEducationgtElement count is count(RESResumeRESEducation) ltEducationgtltAddressgtElement count is count(RESResumeRESAddress) ltAddressgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the min() function
The following query displays the education element for which the GPA value is minimum using the min() function
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = min(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the max() function
The following query displays the education element for which the GPA value is maximum using the max() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = max(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the avg() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using theavg() function
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt avg(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoNewYorkTempLow) ltAvgLowgt
ltNewYorkgtltBostongt
ltAvgHighgt avg(WeatherInfoBostonTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Example Using the sum() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using the
Copy Code
Copy Code
Copy Code
sum() and count() functions
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt sum(WeatherInfoNewYorkTempHigh) div count
(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt sum(WeatherInfoNewYorkTempLow) div count
(WeatherInfoNewYorkTempLow) ltAvgLowgtltNewYorkgtltBostongt
ltAvgHighgt sum(WeatherInfoBostonTempHigh) div count(WeatherInfoBostonTempHigh) ltAvgHighgt
ltAvgLowgt sum(WeatherInfoBostonTempLow) div count(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Context Functions
You can use the context functions to obtain the contextual properties of a context item SQL Server 2005 implements twocontext functionsmdashlast() and position() The last() function can be used to determine the number of items in asequence and the position() function can be used to obtain the position of a context item Both the last() and position() functions without an argument can only be used in the context of a context-dependent predicate (ie inside []) in SQLServer 2005
Example Using the last() function
The following query retrieves the last address element for a candidate using the last() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[last()]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the position() function
The following query retrieves the first two address elements for a candidate using the position() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[position()lt=2]
) as Result
Copy Code
Copy Code
Copy Code
FROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type-Related Expressions
XQuery supports various types of expressions or operators that are based on the type information These expressions canbe classified as type assertion expressions type inspection expressions and type casting expressions These expressionsare discussed briefly in the following sections
Type Assertion Expressions
as xsTYPE clause in for statement
You can use the as clause to specify the type for the binding variable used in the for statement
When a type is declared for the binding variable binding values that are not of the declared type would result in typeerror The xsTYPE clause is not a cast expression but it serves as a type assertion
Example Using as xsTYPE clause with for statement
The following query binds the address node sequence to a variable $A which is defined as type element(RESAddress)
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A as element(RESAddress) in RESResumeRESAddressreturn
$A) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Type Inspection Expressions
instance of xsTYPE operator
The instance of operator helps identify the runtime type of an item in an XML document
Example Using instance of xsTYPE operator
The following query checks to see if the type of an address node identified by an XPath expression matches element() typeor not
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] instance of element() )then
ltResultgtSelected node is an ElementltResultgtelse
ltResultgtSelected node is not an ElementltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type Casting Expressions
Implicit Type Casting
The XQuery engine performs implicit type casting for numeric types and untypedAtomic values in expressions that containarithmetic operations or function invocations This process is known as type promotion Type promotion occurs when anexpression results in a numeric type that is incompatible with the expected numeric type Type promotion is performed bycasting the resulting expression to the required type
Example Implicit type casting
The following query performs an arithmetic operation on a decimal value and a double value In the current scenario the
Copy Code
Copy Code
values in the expression are added only after promoting the xsdecimal value to xsdouble
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(
ltResultgt xsdecimal(1055) + xsdouble(15e1) ltResultgt) as Result
Explicit Type Casting
Typed value constructors
XQuery provides constructor functions for all built-in types defined in the XML Schema specification These constructorsare useful for constructing typed values and also for casting values from one type to another XQuery also makesconstructors available for types that are defined in imported schemas
Example Using a value constructor for constructing values
The following query returns all Employment nodes for which the StartDate is greater than a value constructed usingconstructor for type xsdate
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentwhere $EMPRESEmpStartDate gt xsdate(1995-01-01)return
$EMP) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using a value constructor for typecasting
The following query selects all Education nodes where the GPA is greater than or equal to 38 for the candidate whoseJobCandidateID is 2 This query uses the value constructor for xsdecimal for typecasting the value of EduGPA fromxsstring to xsdecimal
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) ge 38return
element Educationelement Level string($EDRESEduLevel)element StartDate string($EDRESEduStartDate)element EndDate string($EDRESEduEndDate)element Degree string($EDRESEduDegree)element GPA string($EDRESEduGPA)element GPAScale string($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
cast as xsTYPE Operator
XQuery in SQL Server 2005 supports the cast as TYPE operator which is useful for performing explicit type castingExplicit type casting can also be performed using the xsTYPE() constructors which are more convenient to write thanthe cast as TYPE operator
Example Using cast as xsTYPE operator
The following query generates an XML that contains typed values of selected elements from Education node set for acandidate whose JobCandidateID is 3
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level $EDRESEduLevel cast as xsstring element StartDate $EDRESEduStartDate cast as xsdate element EndDate $EDRESEduEndDate cast as xsdate element Degree $EDRESEduDegree cast as xsstring element GPA $EDRESEduGPA cast as xsdecimal element GPAScale $EDRESEduGPAScale cast as xsdecimal
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using xsTYPE() operator
The following query generates the same results as the query in the previous example using the xsTYPE() operatorinstead of the cast as xsTYPE operator
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level xsstring($EDRESEduLevel) element StartDate xsdate($EDRESEduStartDate) element EndDate xsdate($EDRESEduEndDate) element Degree xsstring($EDRESEduDegree) element GPA xsdecimal($EDRESEduGPA) element GPAScale xsdecimal($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Accessing Relational Columns and Variables
When writing queries using XQuery it is not uncommon to have the requirement for accessing relational columns andvariables from within the query SQL Server 2005 caters to this requirement by implementing two functionsmdashsqlcolumn() and sqlvariable()
The function sqlcolumn() can be used to access non-XML columns in a relational table from within a query This functionis useful for scenarios such as aggregating information from XML and non-XML type columns of one or more tables usingthe values of non-XML columns to filter the results of an XQuery and so on The functions sqlcolumn() andsqlvariable() cannot be used with datetime CLR user-defined functions or XML
Example Using sqlcolumn() function
The following query generates an XML that contains values from the CustomerID and Name columns of non-XML datatype and values of YearOpened NumberOfEmployees AnnualSales and AnnualRevenue elements from theDemographics column
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyelement CustomerInfo
element CustomerID sqlcolumn(StoreCustomerID) element Name sqlcolumn(StoreName) element YearOpened string((STStoreSurveySTYearOpened)[1]) element NumberOfEmployees string((STStoreSurveySTNumberEmployees)[1]) element AnnualSales string((STStoreSurveySTAnnualSales)[1]) element AnnualRevenue string((STStoreSurveySTAnnualRevenue)[1])
) as Result
Copy Code
Copy Code
Copy Code
FROM [Sales][Store] StoreWHERE StoreCustomerID = 4
Example Using sqlvariable() function
The following stored procedure returns home address nodes of a specified candidate by using the value of theAddrType variable in the XQuery where clause to filter the results of the query
CREATE PROCEDURE [GetCandidateAddress]JobCandidateID [int]AddrType [varchar](20)
ASBEGIN
SET NOCOUNT ON
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $A[ RESAddrType = sqlvariable(AddrType) ]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = JobCandidateID
END
Example Using sqlvariable() function in conjunction with the exist() method of the XML data type
The following query returns resumes of candidates who hold a Bachelors degree with a major in Business
DECLARE EducationLevel varchar(20)SET EducationLevel = Bachelor
DECLARE Major varchar(20)SET Major = Business
SELECT JobCandidateID ResumeFROM [HumanResources][JobCandidate]WHERE Resumeexist (
declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[ RESEduLevel = sqlvariable(EducationLevel) and RESEduMajor
= sqlvariable(Major) ]) = 1
Non-Supported Features and Workarounds
Current implementation of XQuery in SQL Server 2005 does not support the following features
l The let clause The let clause which is a part of the FLWOR expression is useful for binding a variable to the resultsof an expression WorkaroundmdashInstead of using the let clause use an inline expression
l Range expression (to operator) A range expression can be used to construct a sequence of consecutive integersusing the to operator For example using a range expression such as (6 to 10) it is possible to construct thesequence (6 7 8 9 10) WorkaroundmdashInstead of using the to operator list all items in your sequence
l Type information Some features that are based on type system such as typeswitch treat as castable andvalidate expressions are currently not supported
l The functionality of a typeswitch expression is similar to the switch-case construct available in otherprogramming languages In a switch-case statement the branchescases are selected based on the value of theargument passed to the switch In a typeswitch expression the branches are selected based on the type of theargument passed to typeswitch Workaroundmdashuse if then else and instance of
l The treat as expression can be used to change the static type of the result of an expression to a specific statictype and raises a static type error if the static type of the expression does not match the specified type It doesnot change the dynamic type or value of the expression Workaroundmdashnone
l The castable expression is useful for checking whether an atomic value can be cast to the specified typeWorkaroundmdashInstead of using the expression $x castable as T use the expression empty(data($x)) or not(empty(T($x)))
Copy Code
Copy Code
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
simple XPath expressions The where clause is used to eliminate unwanted values in the result set An example is asfollows
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(for $i in (1 2 3) $j in (3 4 5)where $i lt $jreturn sum($i + $j)) as Result
l If you want to sort the result set based on a sorting expression Sorting is defined on the result set using the orderby clause
l When you want to define the shape of the returned result set using the results obtained from the for clause Thereturn statement is used to perform the shaping of the result set
In all other cases using XPath expressions is recommended
Operators in XQuery
As a functional language XQuery in SQL Server 2005 supports various types of functions and operators that can begrouped under the following categories
l Arithmetic operators
l Comparison operators
l Logical operators
Table 3 Operators supported in SQL Server 2005
Arithmetic Operators
SQL Server 2005 supports five arithmetic operators These are + b div and mod Currently it does not support idiv
Example Converting selected values of store survey information
This example is based on the [Sales][Store] table in the AdventureWorks database The following query returns values ofAnnualSales AnnualRevenue in yen and the store area in square meters for a store whose CustomerID is 3
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyfor $S in STStoreSurveyreturn
ltStoreDetailsSalesInYen = $SSTAnnualSales1068100 RevenueInYen = $SSTAnnualRevenue1068100 StoreAreaInSqMeters = $SSTSquareFeet00929 gt
ltStoreDetailsgt) as ResultFROM [Sales][Store]WHERE CustomerID = 3
Comparison Operators
Copy Code
Type Operators
Arithmetic operators +-div mod
General comparison operators = = lt gt lt= gt=
Value comparison operators eq ne lt gt le ge
Node comparison operator is
Node order comparison operators gtgt ltlt
Logical operators and or
Copy Code
SQL Server 2005 has implemented support for four types of comparison operatorsmdashgeneral comparison operators valuecomparison operators node comparison operators and node order comparison operators
General comparison operators
General comparison operators help compare atomic values sequences or a combination of the two General comparisonoperators are = = lt gt lt= and gt= A general comparison is existentially quantified meaning that any match willresult in true
Example Selecting all address elements where the address type is not set to Home
The following query selects all Address nodes where the type of address is not set to Home and the JobCandidateID is3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $ARESAddrType[=Home]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Value comparison operators
Value comparison operators help compare atomic values Value comparison operators supported by SQL Server 2005 areeq ne lt gt le and ge The current implementation of XQuery with respect to promoting untyped atomic values is notaligned with the July 2004 draft of the XQuery specification The untyped atomic type is promoted to the type of the otheroperand instead of xsstring as specified in the XQuery specification This is to maintain consistency across general andvalue comparison operators which we consider more important than making the value comparison transitive
Example Selecting all education elements where the GPA is greater than 35
The following query selects all Education nodes where the GPA is greater than 35 for the candidate whoseJobCandidateID is 2
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal($EDRESEduGPA) gt 35return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Node comparison operators
You can use the node comparison operator is to compare two nodes to determine if they represent the same node or notThe node comparison operator accepts two operands that are of type node
Example Comparing two address nodes to check their identity
The following query compares two address nodes to check if they represent the same node in the document
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] is (RESAddress)[1] )then
ltResultgtNodes are equalltResultgtelse
ltResultgtNodes are not equalltResultgt) as ResultFROM [HumanResources][JobCandidate]
Copy Code
Copy Code
Copy Code
WHERE JobCandidateID = 3
Node order comparison operators
You can use the node order comparison operators to ascertain the order of two nodes in a document The node ordercomparison operators supported by SQL Sever 2005 are gtgt and ltlt and both the operators accept two operands The gtgtoperator returns true if the left operand precedes the right operand in document order and the ltlt operator returns trueif the left operand follows the right operand in document order
Example Comparing the order of two address nodes
The following query compares the order of two address nodes for a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddressRESAddrType[=Home])[1] ltlt
(RESResumeRESAddressRESAddrType[=Permanent])[1] )then
ltResultgtHome address precedes Permanent addressltResultgtelse
ltResultgtHome address follows Permanent addressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Logical Operators
The logical operators supported by XQuery in SQL Server 2005 are and and or The value of any logical expressionformed using these operators can be either true or false
Example Using the and operator to create a logical expression
The following query returns the candidates education element that contains bachelor level business degree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[RESEduLevel=Bachelor and RESEduMajor=Business]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
The if-then-else Construct
Like other functional languages XQuery supports the if-then-else construct You can use the if-then-else statement toperform operations based on the value of a conditional expression
Example Using a conditional expression
The following query displays the type of address that is specified in the resume for a candidate whose JobCandidateID is3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddressreturn
if ( $ARESAddrType eq Home )then
ltResultgtHome AddressltResultgtelse
ltResultgtOther AddressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Copy Code
Copy Code
Copy Code
Constructing XML Using XQuery
XQuery constructors enable you to create XML structures within a query Constructors are available for elementsattributes processing instructions text nodes and comments
The following examples illustrate these approaches to constructing XML
Example Using constant expressions
The following query displays employment history details constructed using constant expressions
SELECT Resumequery(ltEmployer IndustryCategory=ITServicesgtltOrganizationgtABC TechnologiesltOrganizationgtltJobTitlegtSoftware EngineerltJobTitlegtltStartDategt2001-10-01ltStartDategtltEndDategt2003-05-09ltEndDategt
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]
WHERE JobCandidateID = 3
Example Using data obtained dynamically
The following query displays employment history details constructed using the results obtained from a query for acandidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmployer Organization = $EMPRESEmpOrgName gt $EMPRESEmpStartDate $EMPRESEmpEndDate $EMPRESEmpJobTitle
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using constant names for computed element and attribute constructors
The following query displays the employment history of a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
element Employerattribute Organization $EMPRESEmpOrgName element StartDate string($EMPRESEmpStartDate) element EndDate string($EMPRESEmpEndDate) element JobTitle string($EMPRESEmpJobTitle)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Performing XQuery Construction vs Shaping Using FOR XML
Some applications have a requirement to generate XML from a rowset On the server XML can be generated using a FORXML clause or XQuery constructions or XML DML operations Recommendations on using FOR XML and XQueryconstructors for constructing XML are as follows
Copy Code
Copy Code
Copy Code
l If XML is to be aggregated from multiple columns and multiple rows then FOR XML is the only choice
l If a single XML instance is to be reshaped then it can be done using XQuery as well as FOR XML XQuery might befaster since the FOR XML approach will require multiple invocations of XML data type methods on the XML instance
l You can use multiple XML DML statements to construct an XML instance This approach is significantly slower thanXQuery construction
l Use the new TYPE directive available with the FOR XML clause in SQL Server 2005 to generate the result of a FORXML query as an instance of XML data type
Built-in XQuery Functions
Implementation of XQuery in SQL Server 2005 supports a subset of the built-in functions of XQuery 10 and XPath 20These functions include data accessor functions string manipulation functions aggregate functions context functionsnumeric functions Boolean functions node functions and sequence functions The following sections explore some ofthese functions
Data Accessors
You can use the data accessor functions to extract values of nodes as strings or typed values XQuery supports two typesof data accessor functions string() which extracts the string value of an item and data() which gets the typed value Ifthe node is not a text node an attribute node or an element node then the data() function throws a static error If thenode is a document node of an untyped XML instance then data() returns a string value of the document The data()function returns a static error if the node is a complex typed element
Example Using the string() function
See the Using constant names for computed element and attribute constructors example in the section Constructing XMLUsing XQuery in this paper for a query that generates the employment history of a candidate by using the string()function and computed element constructors
Example Using the data() function
The following query generates the employment history of a candidate by using the data() function and computed elementconstructors
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) gt 35return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
String Manipulation
XQuery supports four string manipulation functions
l concat() Helps concatenate two or more strings
l contains() Helps determine whether or not a string specified as the first operand contains another string specifiedas the second operand The length of the search string is limited to 4000 Unicode characters
l substring() Helps extract portion of a string from another string known as source string
l string-length() Helps calculate the length of a string
The current release of SQL Server 2005 supports only the Unicode codepoint collation
Example Using the concat() and substring() functions
The following query generates the employment history of a candidate by concatenating the values of start date enddate organization name and job title
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmploymentgtconcat( substring(string($EMPRESEmpStartDate)110) to
substring(string($EMPRESEmpEndDate)110) string($EMPRESEmpOrgName) string($EMPRESEmpJobTitle) )
ltEmploymentgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the contains() function
The following query demonstrates the use of the contains() function by displaying Education details for a node thatcontains the string science in the value of the element EduDegree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere contains($EDRESEduDegree Science)return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Aggregate Functions
Aggregate functions operate on a sequence of items and return the aggregate values of the sequence Aggregate functionscurrently supported in the XQuery support in SQL Server 2005 are count() min() max() avg() and sum() Thefunctions min() and max() accept only base types that support the gt operator (ie the three built-in numeric basetypes the datetime base types xsstring xsboolean and xdtuntypedAtomic) A sequence of mixed types is notsupported in these functions Furthermore xdtuntypedAtomic is treated as xsdouble
For avg() and sum() the type of the passed expression needs to be a subtype of one of the three built-in numeric basetypes or untypedAtomic (but not a mixture xdtuntypedAtomic is treated as xsdouble)
The count() function returns the number of items in a sequence
Example Using the count() function
The following query displays the count of employment education and address elements present in the documentusing the count() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeltEmploymentgtElement count is count(RESResumeRESAddress) ltEmploymentgtltEducationgtElement count is count(RESResumeRESEducation) ltEducationgtltAddressgtElement count is count(RESResumeRESAddress) ltAddressgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the min() function
The following query displays the education element for which the GPA value is minimum using the min() function
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = min(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the max() function
The following query displays the education element for which the GPA value is maximum using the max() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = max(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the avg() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using theavg() function
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt avg(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoNewYorkTempLow) ltAvgLowgt
ltNewYorkgtltBostongt
ltAvgHighgt avg(WeatherInfoBostonTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Example Using the sum() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using the
Copy Code
Copy Code
Copy Code
sum() and count() functions
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt sum(WeatherInfoNewYorkTempHigh) div count
(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt sum(WeatherInfoNewYorkTempLow) div count
(WeatherInfoNewYorkTempLow) ltAvgLowgtltNewYorkgtltBostongt
ltAvgHighgt sum(WeatherInfoBostonTempHigh) div count(WeatherInfoBostonTempHigh) ltAvgHighgt
ltAvgLowgt sum(WeatherInfoBostonTempLow) div count(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Context Functions
You can use the context functions to obtain the contextual properties of a context item SQL Server 2005 implements twocontext functionsmdashlast() and position() The last() function can be used to determine the number of items in asequence and the position() function can be used to obtain the position of a context item Both the last() and position() functions without an argument can only be used in the context of a context-dependent predicate (ie inside []) in SQLServer 2005
Example Using the last() function
The following query retrieves the last address element for a candidate using the last() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[last()]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the position() function
The following query retrieves the first two address elements for a candidate using the position() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[position()lt=2]
) as Result
Copy Code
Copy Code
Copy Code
FROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type-Related Expressions
XQuery supports various types of expressions or operators that are based on the type information These expressions canbe classified as type assertion expressions type inspection expressions and type casting expressions These expressionsare discussed briefly in the following sections
Type Assertion Expressions
as xsTYPE clause in for statement
You can use the as clause to specify the type for the binding variable used in the for statement
When a type is declared for the binding variable binding values that are not of the declared type would result in typeerror The xsTYPE clause is not a cast expression but it serves as a type assertion
Example Using as xsTYPE clause with for statement
The following query binds the address node sequence to a variable $A which is defined as type element(RESAddress)
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A as element(RESAddress) in RESResumeRESAddressreturn
$A) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Type Inspection Expressions
instance of xsTYPE operator
The instance of operator helps identify the runtime type of an item in an XML document
Example Using instance of xsTYPE operator
The following query checks to see if the type of an address node identified by an XPath expression matches element() typeor not
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] instance of element() )then
ltResultgtSelected node is an ElementltResultgtelse
ltResultgtSelected node is not an ElementltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type Casting Expressions
Implicit Type Casting
The XQuery engine performs implicit type casting for numeric types and untypedAtomic values in expressions that containarithmetic operations or function invocations This process is known as type promotion Type promotion occurs when anexpression results in a numeric type that is incompatible with the expected numeric type Type promotion is performed bycasting the resulting expression to the required type
Example Implicit type casting
The following query performs an arithmetic operation on a decimal value and a double value In the current scenario the
Copy Code
Copy Code
values in the expression are added only after promoting the xsdecimal value to xsdouble
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(
ltResultgt xsdecimal(1055) + xsdouble(15e1) ltResultgt) as Result
Explicit Type Casting
Typed value constructors
XQuery provides constructor functions for all built-in types defined in the XML Schema specification These constructorsare useful for constructing typed values and also for casting values from one type to another XQuery also makesconstructors available for types that are defined in imported schemas
Example Using a value constructor for constructing values
The following query returns all Employment nodes for which the StartDate is greater than a value constructed usingconstructor for type xsdate
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentwhere $EMPRESEmpStartDate gt xsdate(1995-01-01)return
$EMP) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using a value constructor for typecasting
The following query selects all Education nodes where the GPA is greater than or equal to 38 for the candidate whoseJobCandidateID is 2 This query uses the value constructor for xsdecimal for typecasting the value of EduGPA fromxsstring to xsdecimal
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) ge 38return
element Educationelement Level string($EDRESEduLevel)element StartDate string($EDRESEduStartDate)element EndDate string($EDRESEduEndDate)element Degree string($EDRESEduDegree)element GPA string($EDRESEduGPA)element GPAScale string($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
cast as xsTYPE Operator
XQuery in SQL Server 2005 supports the cast as TYPE operator which is useful for performing explicit type castingExplicit type casting can also be performed using the xsTYPE() constructors which are more convenient to write thanthe cast as TYPE operator
Example Using cast as xsTYPE operator
The following query generates an XML that contains typed values of selected elements from Education node set for acandidate whose JobCandidateID is 3
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level $EDRESEduLevel cast as xsstring element StartDate $EDRESEduStartDate cast as xsdate element EndDate $EDRESEduEndDate cast as xsdate element Degree $EDRESEduDegree cast as xsstring element GPA $EDRESEduGPA cast as xsdecimal element GPAScale $EDRESEduGPAScale cast as xsdecimal
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using xsTYPE() operator
The following query generates the same results as the query in the previous example using the xsTYPE() operatorinstead of the cast as xsTYPE operator
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level xsstring($EDRESEduLevel) element StartDate xsdate($EDRESEduStartDate) element EndDate xsdate($EDRESEduEndDate) element Degree xsstring($EDRESEduDegree) element GPA xsdecimal($EDRESEduGPA) element GPAScale xsdecimal($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Accessing Relational Columns and Variables
When writing queries using XQuery it is not uncommon to have the requirement for accessing relational columns andvariables from within the query SQL Server 2005 caters to this requirement by implementing two functionsmdashsqlcolumn() and sqlvariable()
The function sqlcolumn() can be used to access non-XML columns in a relational table from within a query This functionis useful for scenarios such as aggregating information from XML and non-XML type columns of one or more tables usingthe values of non-XML columns to filter the results of an XQuery and so on The functions sqlcolumn() andsqlvariable() cannot be used with datetime CLR user-defined functions or XML
Example Using sqlcolumn() function
The following query generates an XML that contains values from the CustomerID and Name columns of non-XML datatype and values of YearOpened NumberOfEmployees AnnualSales and AnnualRevenue elements from theDemographics column
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyelement CustomerInfo
element CustomerID sqlcolumn(StoreCustomerID) element Name sqlcolumn(StoreName) element YearOpened string((STStoreSurveySTYearOpened)[1]) element NumberOfEmployees string((STStoreSurveySTNumberEmployees)[1]) element AnnualSales string((STStoreSurveySTAnnualSales)[1]) element AnnualRevenue string((STStoreSurveySTAnnualRevenue)[1])
) as Result
Copy Code
Copy Code
Copy Code
FROM [Sales][Store] StoreWHERE StoreCustomerID = 4
Example Using sqlvariable() function
The following stored procedure returns home address nodes of a specified candidate by using the value of theAddrType variable in the XQuery where clause to filter the results of the query
CREATE PROCEDURE [GetCandidateAddress]JobCandidateID [int]AddrType [varchar](20)
ASBEGIN
SET NOCOUNT ON
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $A[ RESAddrType = sqlvariable(AddrType) ]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = JobCandidateID
END
Example Using sqlvariable() function in conjunction with the exist() method of the XML data type
The following query returns resumes of candidates who hold a Bachelors degree with a major in Business
DECLARE EducationLevel varchar(20)SET EducationLevel = Bachelor
DECLARE Major varchar(20)SET Major = Business
SELECT JobCandidateID ResumeFROM [HumanResources][JobCandidate]WHERE Resumeexist (
declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[ RESEduLevel = sqlvariable(EducationLevel) and RESEduMajor
= sqlvariable(Major) ]) = 1
Non-Supported Features and Workarounds
Current implementation of XQuery in SQL Server 2005 does not support the following features
l The let clause The let clause which is a part of the FLWOR expression is useful for binding a variable to the resultsof an expression WorkaroundmdashInstead of using the let clause use an inline expression
l Range expression (to operator) A range expression can be used to construct a sequence of consecutive integersusing the to operator For example using a range expression such as (6 to 10) it is possible to construct thesequence (6 7 8 9 10) WorkaroundmdashInstead of using the to operator list all items in your sequence
l Type information Some features that are based on type system such as typeswitch treat as castable andvalidate expressions are currently not supported
l The functionality of a typeswitch expression is similar to the switch-case construct available in otherprogramming languages In a switch-case statement the branchescases are selected based on the value of theargument passed to the switch In a typeswitch expression the branches are selected based on the type of theargument passed to typeswitch Workaroundmdashuse if then else and instance of
l The treat as expression can be used to change the static type of the result of an expression to a specific statictype and raises a static type error if the static type of the expression does not match the specified type It doesnot change the dynamic type or value of the expression Workaroundmdashnone
l The castable expression is useful for checking whether an atomic value can be cast to the specified typeWorkaroundmdashInstead of using the expression $x castable as T use the expression empty(data($x)) or not(empty(T($x)))
Copy Code
Copy Code
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
SQL Server 2005 has implemented support for four types of comparison operatorsmdashgeneral comparison operators valuecomparison operators node comparison operators and node order comparison operators
General comparison operators
General comparison operators help compare atomic values sequences or a combination of the two General comparisonoperators are = = lt gt lt= and gt= A general comparison is existentially quantified meaning that any match willresult in true
Example Selecting all address elements where the address type is not set to Home
The following query selects all Address nodes where the type of address is not set to Home and the JobCandidateID is3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $ARESAddrType[=Home]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Value comparison operators
Value comparison operators help compare atomic values Value comparison operators supported by SQL Server 2005 areeq ne lt gt le and ge The current implementation of XQuery with respect to promoting untyped atomic values is notaligned with the July 2004 draft of the XQuery specification The untyped atomic type is promoted to the type of the otheroperand instead of xsstring as specified in the XQuery specification This is to maintain consistency across general andvalue comparison operators which we consider more important than making the value comparison transitive
Example Selecting all education elements where the GPA is greater than 35
The following query selects all Education nodes where the GPA is greater than 35 for the candidate whoseJobCandidateID is 2
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal($EDRESEduGPA) gt 35return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Node comparison operators
You can use the node comparison operator is to compare two nodes to determine if they represent the same node or notThe node comparison operator accepts two operands that are of type node
Example Comparing two address nodes to check their identity
The following query compares two address nodes to check if they represent the same node in the document
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] is (RESAddress)[1] )then
ltResultgtNodes are equalltResultgtelse
ltResultgtNodes are not equalltResultgt) as ResultFROM [HumanResources][JobCandidate]
Copy Code
Copy Code
Copy Code
WHERE JobCandidateID = 3
Node order comparison operators
You can use the node order comparison operators to ascertain the order of two nodes in a document The node ordercomparison operators supported by SQL Sever 2005 are gtgt and ltlt and both the operators accept two operands The gtgtoperator returns true if the left operand precedes the right operand in document order and the ltlt operator returns trueif the left operand follows the right operand in document order
Example Comparing the order of two address nodes
The following query compares the order of two address nodes for a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddressRESAddrType[=Home])[1] ltlt
(RESResumeRESAddressRESAddrType[=Permanent])[1] )then
ltResultgtHome address precedes Permanent addressltResultgtelse
ltResultgtHome address follows Permanent addressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Logical Operators
The logical operators supported by XQuery in SQL Server 2005 are and and or The value of any logical expressionformed using these operators can be either true or false
Example Using the and operator to create a logical expression
The following query returns the candidates education element that contains bachelor level business degree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[RESEduLevel=Bachelor and RESEduMajor=Business]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
The if-then-else Construct
Like other functional languages XQuery supports the if-then-else construct You can use the if-then-else statement toperform operations based on the value of a conditional expression
Example Using a conditional expression
The following query displays the type of address that is specified in the resume for a candidate whose JobCandidateID is3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddressreturn
if ( $ARESAddrType eq Home )then
ltResultgtHome AddressltResultgtelse
ltResultgtOther AddressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Copy Code
Copy Code
Copy Code
Constructing XML Using XQuery
XQuery constructors enable you to create XML structures within a query Constructors are available for elementsattributes processing instructions text nodes and comments
The following examples illustrate these approaches to constructing XML
Example Using constant expressions
The following query displays employment history details constructed using constant expressions
SELECT Resumequery(ltEmployer IndustryCategory=ITServicesgtltOrganizationgtABC TechnologiesltOrganizationgtltJobTitlegtSoftware EngineerltJobTitlegtltStartDategt2001-10-01ltStartDategtltEndDategt2003-05-09ltEndDategt
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]
WHERE JobCandidateID = 3
Example Using data obtained dynamically
The following query displays employment history details constructed using the results obtained from a query for acandidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmployer Organization = $EMPRESEmpOrgName gt $EMPRESEmpStartDate $EMPRESEmpEndDate $EMPRESEmpJobTitle
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using constant names for computed element and attribute constructors
The following query displays the employment history of a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
element Employerattribute Organization $EMPRESEmpOrgName element StartDate string($EMPRESEmpStartDate) element EndDate string($EMPRESEmpEndDate) element JobTitle string($EMPRESEmpJobTitle)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Performing XQuery Construction vs Shaping Using FOR XML
Some applications have a requirement to generate XML from a rowset On the server XML can be generated using a FORXML clause or XQuery constructions or XML DML operations Recommendations on using FOR XML and XQueryconstructors for constructing XML are as follows
Copy Code
Copy Code
Copy Code
l If XML is to be aggregated from multiple columns and multiple rows then FOR XML is the only choice
l If a single XML instance is to be reshaped then it can be done using XQuery as well as FOR XML XQuery might befaster since the FOR XML approach will require multiple invocations of XML data type methods on the XML instance
l You can use multiple XML DML statements to construct an XML instance This approach is significantly slower thanXQuery construction
l Use the new TYPE directive available with the FOR XML clause in SQL Server 2005 to generate the result of a FORXML query as an instance of XML data type
Built-in XQuery Functions
Implementation of XQuery in SQL Server 2005 supports a subset of the built-in functions of XQuery 10 and XPath 20These functions include data accessor functions string manipulation functions aggregate functions context functionsnumeric functions Boolean functions node functions and sequence functions The following sections explore some ofthese functions
Data Accessors
You can use the data accessor functions to extract values of nodes as strings or typed values XQuery supports two typesof data accessor functions string() which extracts the string value of an item and data() which gets the typed value Ifthe node is not a text node an attribute node or an element node then the data() function throws a static error If thenode is a document node of an untyped XML instance then data() returns a string value of the document The data()function returns a static error if the node is a complex typed element
Example Using the string() function
See the Using constant names for computed element and attribute constructors example in the section Constructing XMLUsing XQuery in this paper for a query that generates the employment history of a candidate by using the string()function and computed element constructors
Example Using the data() function
The following query generates the employment history of a candidate by using the data() function and computed elementconstructors
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) gt 35return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
String Manipulation
XQuery supports four string manipulation functions
l concat() Helps concatenate two or more strings
l contains() Helps determine whether or not a string specified as the first operand contains another string specifiedas the second operand The length of the search string is limited to 4000 Unicode characters
l substring() Helps extract portion of a string from another string known as source string
l string-length() Helps calculate the length of a string
The current release of SQL Server 2005 supports only the Unicode codepoint collation
Example Using the concat() and substring() functions
The following query generates the employment history of a candidate by concatenating the values of start date enddate organization name and job title
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmploymentgtconcat( substring(string($EMPRESEmpStartDate)110) to
substring(string($EMPRESEmpEndDate)110) string($EMPRESEmpOrgName) string($EMPRESEmpJobTitle) )
ltEmploymentgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the contains() function
The following query demonstrates the use of the contains() function by displaying Education details for a node thatcontains the string science in the value of the element EduDegree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere contains($EDRESEduDegree Science)return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Aggregate Functions
Aggregate functions operate on a sequence of items and return the aggregate values of the sequence Aggregate functionscurrently supported in the XQuery support in SQL Server 2005 are count() min() max() avg() and sum() Thefunctions min() and max() accept only base types that support the gt operator (ie the three built-in numeric basetypes the datetime base types xsstring xsboolean and xdtuntypedAtomic) A sequence of mixed types is notsupported in these functions Furthermore xdtuntypedAtomic is treated as xsdouble
For avg() and sum() the type of the passed expression needs to be a subtype of one of the three built-in numeric basetypes or untypedAtomic (but not a mixture xdtuntypedAtomic is treated as xsdouble)
The count() function returns the number of items in a sequence
Example Using the count() function
The following query displays the count of employment education and address elements present in the documentusing the count() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeltEmploymentgtElement count is count(RESResumeRESAddress) ltEmploymentgtltEducationgtElement count is count(RESResumeRESEducation) ltEducationgtltAddressgtElement count is count(RESResumeRESAddress) ltAddressgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the min() function
The following query displays the education element for which the GPA value is minimum using the min() function
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = min(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the max() function
The following query displays the education element for which the GPA value is maximum using the max() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = max(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the avg() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using theavg() function
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt avg(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoNewYorkTempLow) ltAvgLowgt
ltNewYorkgtltBostongt
ltAvgHighgt avg(WeatherInfoBostonTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Example Using the sum() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using the
Copy Code
Copy Code
Copy Code
sum() and count() functions
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt sum(WeatherInfoNewYorkTempHigh) div count
(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt sum(WeatherInfoNewYorkTempLow) div count
(WeatherInfoNewYorkTempLow) ltAvgLowgtltNewYorkgtltBostongt
ltAvgHighgt sum(WeatherInfoBostonTempHigh) div count(WeatherInfoBostonTempHigh) ltAvgHighgt
ltAvgLowgt sum(WeatherInfoBostonTempLow) div count(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Context Functions
You can use the context functions to obtain the contextual properties of a context item SQL Server 2005 implements twocontext functionsmdashlast() and position() The last() function can be used to determine the number of items in asequence and the position() function can be used to obtain the position of a context item Both the last() and position() functions without an argument can only be used in the context of a context-dependent predicate (ie inside []) in SQLServer 2005
Example Using the last() function
The following query retrieves the last address element for a candidate using the last() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[last()]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the position() function
The following query retrieves the first two address elements for a candidate using the position() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[position()lt=2]
) as Result
Copy Code
Copy Code
Copy Code
FROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type-Related Expressions
XQuery supports various types of expressions or operators that are based on the type information These expressions canbe classified as type assertion expressions type inspection expressions and type casting expressions These expressionsare discussed briefly in the following sections
Type Assertion Expressions
as xsTYPE clause in for statement
You can use the as clause to specify the type for the binding variable used in the for statement
When a type is declared for the binding variable binding values that are not of the declared type would result in typeerror The xsTYPE clause is not a cast expression but it serves as a type assertion
Example Using as xsTYPE clause with for statement
The following query binds the address node sequence to a variable $A which is defined as type element(RESAddress)
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A as element(RESAddress) in RESResumeRESAddressreturn
$A) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Type Inspection Expressions
instance of xsTYPE operator
The instance of operator helps identify the runtime type of an item in an XML document
Example Using instance of xsTYPE operator
The following query checks to see if the type of an address node identified by an XPath expression matches element() typeor not
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] instance of element() )then
ltResultgtSelected node is an ElementltResultgtelse
ltResultgtSelected node is not an ElementltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type Casting Expressions
Implicit Type Casting
The XQuery engine performs implicit type casting for numeric types and untypedAtomic values in expressions that containarithmetic operations or function invocations This process is known as type promotion Type promotion occurs when anexpression results in a numeric type that is incompatible with the expected numeric type Type promotion is performed bycasting the resulting expression to the required type
Example Implicit type casting
The following query performs an arithmetic operation on a decimal value and a double value In the current scenario the
Copy Code
Copy Code
values in the expression are added only after promoting the xsdecimal value to xsdouble
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(
ltResultgt xsdecimal(1055) + xsdouble(15e1) ltResultgt) as Result
Explicit Type Casting
Typed value constructors
XQuery provides constructor functions for all built-in types defined in the XML Schema specification These constructorsare useful for constructing typed values and also for casting values from one type to another XQuery also makesconstructors available for types that are defined in imported schemas
Example Using a value constructor for constructing values
The following query returns all Employment nodes for which the StartDate is greater than a value constructed usingconstructor for type xsdate
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentwhere $EMPRESEmpStartDate gt xsdate(1995-01-01)return
$EMP) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using a value constructor for typecasting
The following query selects all Education nodes where the GPA is greater than or equal to 38 for the candidate whoseJobCandidateID is 2 This query uses the value constructor for xsdecimal for typecasting the value of EduGPA fromxsstring to xsdecimal
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) ge 38return
element Educationelement Level string($EDRESEduLevel)element StartDate string($EDRESEduStartDate)element EndDate string($EDRESEduEndDate)element Degree string($EDRESEduDegree)element GPA string($EDRESEduGPA)element GPAScale string($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
cast as xsTYPE Operator
XQuery in SQL Server 2005 supports the cast as TYPE operator which is useful for performing explicit type castingExplicit type casting can also be performed using the xsTYPE() constructors which are more convenient to write thanthe cast as TYPE operator
Example Using cast as xsTYPE operator
The following query generates an XML that contains typed values of selected elements from Education node set for acandidate whose JobCandidateID is 3
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level $EDRESEduLevel cast as xsstring element StartDate $EDRESEduStartDate cast as xsdate element EndDate $EDRESEduEndDate cast as xsdate element Degree $EDRESEduDegree cast as xsstring element GPA $EDRESEduGPA cast as xsdecimal element GPAScale $EDRESEduGPAScale cast as xsdecimal
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using xsTYPE() operator
The following query generates the same results as the query in the previous example using the xsTYPE() operatorinstead of the cast as xsTYPE operator
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level xsstring($EDRESEduLevel) element StartDate xsdate($EDRESEduStartDate) element EndDate xsdate($EDRESEduEndDate) element Degree xsstring($EDRESEduDegree) element GPA xsdecimal($EDRESEduGPA) element GPAScale xsdecimal($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Accessing Relational Columns and Variables
When writing queries using XQuery it is not uncommon to have the requirement for accessing relational columns andvariables from within the query SQL Server 2005 caters to this requirement by implementing two functionsmdashsqlcolumn() and sqlvariable()
The function sqlcolumn() can be used to access non-XML columns in a relational table from within a query This functionis useful for scenarios such as aggregating information from XML and non-XML type columns of one or more tables usingthe values of non-XML columns to filter the results of an XQuery and so on The functions sqlcolumn() andsqlvariable() cannot be used with datetime CLR user-defined functions or XML
Example Using sqlcolumn() function
The following query generates an XML that contains values from the CustomerID and Name columns of non-XML datatype and values of YearOpened NumberOfEmployees AnnualSales and AnnualRevenue elements from theDemographics column
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyelement CustomerInfo
element CustomerID sqlcolumn(StoreCustomerID) element Name sqlcolumn(StoreName) element YearOpened string((STStoreSurveySTYearOpened)[1]) element NumberOfEmployees string((STStoreSurveySTNumberEmployees)[1]) element AnnualSales string((STStoreSurveySTAnnualSales)[1]) element AnnualRevenue string((STStoreSurveySTAnnualRevenue)[1])
) as Result
Copy Code
Copy Code
Copy Code
FROM [Sales][Store] StoreWHERE StoreCustomerID = 4
Example Using sqlvariable() function
The following stored procedure returns home address nodes of a specified candidate by using the value of theAddrType variable in the XQuery where clause to filter the results of the query
CREATE PROCEDURE [GetCandidateAddress]JobCandidateID [int]AddrType [varchar](20)
ASBEGIN
SET NOCOUNT ON
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $A[ RESAddrType = sqlvariable(AddrType) ]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = JobCandidateID
END
Example Using sqlvariable() function in conjunction with the exist() method of the XML data type
The following query returns resumes of candidates who hold a Bachelors degree with a major in Business
DECLARE EducationLevel varchar(20)SET EducationLevel = Bachelor
DECLARE Major varchar(20)SET Major = Business
SELECT JobCandidateID ResumeFROM [HumanResources][JobCandidate]WHERE Resumeexist (
declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[ RESEduLevel = sqlvariable(EducationLevel) and RESEduMajor
= sqlvariable(Major) ]) = 1
Non-Supported Features and Workarounds
Current implementation of XQuery in SQL Server 2005 does not support the following features
l The let clause The let clause which is a part of the FLWOR expression is useful for binding a variable to the resultsof an expression WorkaroundmdashInstead of using the let clause use an inline expression
l Range expression (to operator) A range expression can be used to construct a sequence of consecutive integersusing the to operator For example using a range expression such as (6 to 10) it is possible to construct thesequence (6 7 8 9 10) WorkaroundmdashInstead of using the to operator list all items in your sequence
l Type information Some features that are based on type system such as typeswitch treat as castable andvalidate expressions are currently not supported
l The functionality of a typeswitch expression is similar to the switch-case construct available in otherprogramming languages In a switch-case statement the branchescases are selected based on the value of theargument passed to the switch In a typeswitch expression the branches are selected based on the type of theargument passed to typeswitch Workaroundmdashuse if then else and instance of
l The treat as expression can be used to change the static type of the result of an expression to a specific statictype and raises a static type error if the static type of the expression does not match the specified type It doesnot change the dynamic type or value of the expression Workaroundmdashnone
l The castable expression is useful for checking whether an atomic value can be cast to the specified typeWorkaroundmdashInstead of using the expression $x castable as T use the expression empty(data($x)) or not(empty(T($x)))
Copy Code
Copy Code
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
WHERE JobCandidateID = 3
Node order comparison operators
You can use the node order comparison operators to ascertain the order of two nodes in a document The node ordercomparison operators supported by SQL Sever 2005 are gtgt and ltlt and both the operators accept two operands The gtgtoperator returns true if the left operand precedes the right operand in document order and the ltlt operator returns trueif the left operand follows the right operand in document order
Example Comparing the order of two address nodes
The following query compares the order of two address nodes for a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddressRESAddrType[=Home])[1] ltlt
(RESResumeRESAddressRESAddrType[=Permanent])[1] )then
ltResultgtHome address precedes Permanent addressltResultgtelse
ltResultgtHome address follows Permanent addressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Logical Operators
The logical operators supported by XQuery in SQL Server 2005 are and and or The value of any logical expressionformed using these operators can be either true or false
Example Using the and operator to create a logical expression
The following query returns the candidates education element that contains bachelor level business degree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[RESEduLevel=Bachelor and RESEduMajor=Business]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
The if-then-else Construct
Like other functional languages XQuery supports the if-then-else construct You can use the if-then-else statement toperform operations based on the value of a conditional expression
Example Using a conditional expression
The following query displays the type of address that is specified in the resume for a candidate whose JobCandidateID is3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddressreturn
if ( $ARESAddrType eq Home )then
ltResultgtHome AddressltResultgtelse
ltResultgtOther AddressltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Copy Code
Copy Code
Copy Code
Constructing XML Using XQuery
XQuery constructors enable you to create XML structures within a query Constructors are available for elementsattributes processing instructions text nodes and comments
The following examples illustrate these approaches to constructing XML
Example Using constant expressions
The following query displays employment history details constructed using constant expressions
SELECT Resumequery(ltEmployer IndustryCategory=ITServicesgtltOrganizationgtABC TechnologiesltOrganizationgtltJobTitlegtSoftware EngineerltJobTitlegtltStartDategt2001-10-01ltStartDategtltEndDategt2003-05-09ltEndDategt
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]
WHERE JobCandidateID = 3
Example Using data obtained dynamically
The following query displays employment history details constructed using the results obtained from a query for acandidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmployer Organization = $EMPRESEmpOrgName gt $EMPRESEmpStartDate $EMPRESEmpEndDate $EMPRESEmpJobTitle
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using constant names for computed element and attribute constructors
The following query displays the employment history of a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
element Employerattribute Organization $EMPRESEmpOrgName element StartDate string($EMPRESEmpStartDate) element EndDate string($EMPRESEmpEndDate) element JobTitle string($EMPRESEmpJobTitle)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Performing XQuery Construction vs Shaping Using FOR XML
Some applications have a requirement to generate XML from a rowset On the server XML can be generated using a FORXML clause or XQuery constructions or XML DML operations Recommendations on using FOR XML and XQueryconstructors for constructing XML are as follows
Copy Code
Copy Code
Copy Code
l If XML is to be aggregated from multiple columns and multiple rows then FOR XML is the only choice
l If a single XML instance is to be reshaped then it can be done using XQuery as well as FOR XML XQuery might befaster since the FOR XML approach will require multiple invocations of XML data type methods on the XML instance
l You can use multiple XML DML statements to construct an XML instance This approach is significantly slower thanXQuery construction
l Use the new TYPE directive available with the FOR XML clause in SQL Server 2005 to generate the result of a FORXML query as an instance of XML data type
Built-in XQuery Functions
Implementation of XQuery in SQL Server 2005 supports a subset of the built-in functions of XQuery 10 and XPath 20These functions include data accessor functions string manipulation functions aggregate functions context functionsnumeric functions Boolean functions node functions and sequence functions The following sections explore some ofthese functions
Data Accessors
You can use the data accessor functions to extract values of nodes as strings or typed values XQuery supports two typesof data accessor functions string() which extracts the string value of an item and data() which gets the typed value Ifthe node is not a text node an attribute node or an element node then the data() function throws a static error If thenode is a document node of an untyped XML instance then data() returns a string value of the document The data()function returns a static error if the node is a complex typed element
Example Using the string() function
See the Using constant names for computed element and attribute constructors example in the section Constructing XMLUsing XQuery in this paper for a query that generates the employment history of a candidate by using the string()function and computed element constructors
Example Using the data() function
The following query generates the employment history of a candidate by using the data() function and computed elementconstructors
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) gt 35return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
String Manipulation
XQuery supports four string manipulation functions
l concat() Helps concatenate two or more strings
l contains() Helps determine whether or not a string specified as the first operand contains another string specifiedas the second operand The length of the search string is limited to 4000 Unicode characters
l substring() Helps extract portion of a string from another string known as source string
l string-length() Helps calculate the length of a string
The current release of SQL Server 2005 supports only the Unicode codepoint collation
Example Using the concat() and substring() functions
The following query generates the employment history of a candidate by concatenating the values of start date enddate organization name and job title
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmploymentgtconcat( substring(string($EMPRESEmpStartDate)110) to
substring(string($EMPRESEmpEndDate)110) string($EMPRESEmpOrgName) string($EMPRESEmpJobTitle) )
ltEmploymentgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the contains() function
The following query demonstrates the use of the contains() function by displaying Education details for a node thatcontains the string science in the value of the element EduDegree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere contains($EDRESEduDegree Science)return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Aggregate Functions
Aggregate functions operate on a sequence of items and return the aggregate values of the sequence Aggregate functionscurrently supported in the XQuery support in SQL Server 2005 are count() min() max() avg() and sum() Thefunctions min() and max() accept only base types that support the gt operator (ie the three built-in numeric basetypes the datetime base types xsstring xsboolean and xdtuntypedAtomic) A sequence of mixed types is notsupported in these functions Furthermore xdtuntypedAtomic is treated as xsdouble
For avg() and sum() the type of the passed expression needs to be a subtype of one of the three built-in numeric basetypes or untypedAtomic (but not a mixture xdtuntypedAtomic is treated as xsdouble)
The count() function returns the number of items in a sequence
Example Using the count() function
The following query displays the count of employment education and address elements present in the documentusing the count() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeltEmploymentgtElement count is count(RESResumeRESAddress) ltEmploymentgtltEducationgtElement count is count(RESResumeRESEducation) ltEducationgtltAddressgtElement count is count(RESResumeRESAddress) ltAddressgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the min() function
The following query displays the education element for which the GPA value is minimum using the min() function
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = min(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the max() function
The following query displays the education element for which the GPA value is maximum using the max() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = max(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the avg() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using theavg() function
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt avg(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoNewYorkTempLow) ltAvgLowgt
ltNewYorkgtltBostongt
ltAvgHighgt avg(WeatherInfoBostonTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Example Using the sum() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using the
Copy Code
Copy Code
Copy Code
sum() and count() functions
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt sum(WeatherInfoNewYorkTempHigh) div count
(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt sum(WeatherInfoNewYorkTempLow) div count
(WeatherInfoNewYorkTempLow) ltAvgLowgtltNewYorkgtltBostongt
ltAvgHighgt sum(WeatherInfoBostonTempHigh) div count(WeatherInfoBostonTempHigh) ltAvgHighgt
ltAvgLowgt sum(WeatherInfoBostonTempLow) div count(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Context Functions
You can use the context functions to obtain the contextual properties of a context item SQL Server 2005 implements twocontext functionsmdashlast() and position() The last() function can be used to determine the number of items in asequence and the position() function can be used to obtain the position of a context item Both the last() and position() functions without an argument can only be used in the context of a context-dependent predicate (ie inside []) in SQLServer 2005
Example Using the last() function
The following query retrieves the last address element for a candidate using the last() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[last()]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the position() function
The following query retrieves the first two address elements for a candidate using the position() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[position()lt=2]
) as Result
Copy Code
Copy Code
Copy Code
FROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type-Related Expressions
XQuery supports various types of expressions or operators that are based on the type information These expressions canbe classified as type assertion expressions type inspection expressions and type casting expressions These expressionsare discussed briefly in the following sections
Type Assertion Expressions
as xsTYPE clause in for statement
You can use the as clause to specify the type for the binding variable used in the for statement
When a type is declared for the binding variable binding values that are not of the declared type would result in typeerror The xsTYPE clause is not a cast expression but it serves as a type assertion
Example Using as xsTYPE clause with for statement
The following query binds the address node sequence to a variable $A which is defined as type element(RESAddress)
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A as element(RESAddress) in RESResumeRESAddressreturn
$A) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Type Inspection Expressions
instance of xsTYPE operator
The instance of operator helps identify the runtime type of an item in an XML document
Example Using instance of xsTYPE operator
The following query checks to see if the type of an address node identified by an XPath expression matches element() typeor not
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] instance of element() )then
ltResultgtSelected node is an ElementltResultgtelse
ltResultgtSelected node is not an ElementltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type Casting Expressions
Implicit Type Casting
The XQuery engine performs implicit type casting for numeric types and untypedAtomic values in expressions that containarithmetic operations or function invocations This process is known as type promotion Type promotion occurs when anexpression results in a numeric type that is incompatible with the expected numeric type Type promotion is performed bycasting the resulting expression to the required type
Example Implicit type casting
The following query performs an arithmetic operation on a decimal value and a double value In the current scenario the
Copy Code
Copy Code
values in the expression are added only after promoting the xsdecimal value to xsdouble
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(
ltResultgt xsdecimal(1055) + xsdouble(15e1) ltResultgt) as Result
Explicit Type Casting
Typed value constructors
XQuery provides constructor functions for all built-in types defined in the XML Schema specification These constructorsare useful for constructing typed values and also for casting values from one type to another XQuery also makesconstructors available for types that are defined in imported schemas
Example Using a value constructor for constructing values
The following query returns all Employment nodes for which the StartDate is greater than a value constructed usingconstructor for type xsdate
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentwhere $EMPRESEmpStartDate gt xsdate(1995-01-01)return
$EMP) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using a value constructor for typecasting
The following query selects all Education nodes where the GPA is greater than or equal to 38 for the candidate whoseJobCandidateID is 2 This query uses the value constructor for xsdecimal for typecasting the value of EduGPA fromxsstring to xsdecimal
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) ge 38return
element Educationelement Level string($EDRESEduLevel)element StartDate string($EDRESEduStartDate)element EndDate string($EDRESEduEndDate)element Degree string($EDRESEduDegree)element GPA string($EDRESEduGPA)element GPAScale string($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
cast as xsTYPE Operator
XQuery in SQL Server 2005 supports the cast as TYPE operator which is useful for performing explicit type castingExplicit type casting can also be performed using the xsTYPE() constructors which are more convenient to write thanthe cast as TYPE operator
Example Using cast as xsTYPE operator
The following query generates an XML that contains typed values of selected elements from Education node set for acandidate whose JobCandidateID is 3
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level $EDRESEduLevel cast as xsstring element StartDate $EDRESEduStartDate cast as xsdate element EndDate $EDRESEduEndDate cast as xsdate element Degree $EDRESEduDegree cast as xsstring element GPA $EDRESEduGPA cast as xsdecimal element GPAScale $EDRESEduGPAScale cast as xsdecimal
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using xsTYPE() operator
The following query generates the same results as the query in the previous example using the xsTYPE() operatorinstead of the cast as xsTYPE operator
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level xsstring($EDRESEduLevel) element StartDate xsdate($EDRESEduStartDate) element EndDate xsdate($EDRESEduEndDate) element Degree xsstring($EDRESEduDegree) element GPA xsdecimal($EDRESEduGPA) element GPAScale xsdecimal($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Accessing Relational Columns and Variables
When writing queries using XQuery it is not uncommon to have the requirement for accessing relational columns andvariables from within the query SQL Server 2005 caters to this requirement by implementing two functionsmdashsqlcolumn() and sqlvariable()
The function sqlcolumn() can be used to access non-XML columns in a relational table from within a query This functionis useful for scenarios such as aggregating information from XML and non-XML type columns of one or more tables usingthe values of non-XML columns to filter the results of an XQuery and so on The functions sqlcolumn() andsqlvariable() cannot be used with datetime CLR user-defined functions or XML
Example Using sqlcolumn() function
The following query generates an XML that contains values from the CustomerID and Name columns of non-XML datatype and values of YearOpened NumberOfEmployees AnnualSales and AnnualRevenue elements from theDemographics column
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyelement CustomerInfo
element CustomerID sqlcolumn(StoreCustomerID) element Name sqlcolumn(StoreName) element YearOpened string((STStoreSurveySTYearOpened)[1]) element NumberOfEmployees string((STStoreSurveySTNumberEmployees)[1]) element AnnualSales string((STStoreSurveySTAnnualSales)[1]) element AnnualRevenue string((STStoreSurveySTAnnualRevenue)[1])
) as Result
Copy Code
Copy Code
Copy Code
FROM [Sales][Store] StoreWHERE StoreCustomerID = 4
Example Using sqlvariable() function
The following stored procedure returns home address nodes of a specified candidate by using the value of theAddrType variable in the XQuery where clause to filter the results of the query
CREATE PROCEDURE [GetCandidateAddress]JobCandidateID [int]AddrType [varchar](20)
ASBEGIN
SET NOCOUNT ON
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $A[ RESAddrType = sqlvariable(AddrType) ]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = JobCandidateID
END
Example Using sqlvariable() function in conjunction with the exist() method of the XML data type
The following query returns resumes of candidates who hold a Bachelors degree with a major in Business
DECLARE EducationLevel varchar(20)SET EducationLevel = Bachelor
DECLARE Major varchar(20)SET Major = Business
SELECT JobCandidateID ResumeFROM [HumanResources][JobCandidate]WHERE Resumeexist (
declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[ RESEduLevel = sqlvariable(EducationLevel) and RESEduMajor
= sqlvariable(Major) ]) = 1
Non-Supported Features and Workarounds
Current implementation of XQuery in SQL Server 2005 does not support the following features
l The let clause The let clause which is a part of the FLWOR expression is useful for binding a variable to the resultsof an expression WorkaroundmdashInstead of using the let clause use an inline expression
l Range expression (to operator) A range expression can be used to construct a sequence of consecutive integersusing the to operator For example using a range expression such as (6 to 10) it is possible to construct thesequence (6 7 8 9 10) WorkaroundmdashInstead of using the to operator list all items in your sequence
l Type information Some features that are based on type system such as typeswitch treat as castable andvalidate expressions are currently not supported
l The functionality of a typeswitch expression is similar to the switch-case construct available in otherprogramming languages In a switch-case statement the branchescases are selected based on the value of theargument passed to the switch In a typeswitch expression the branches are selected based on the type of theargument passed to typeswitch Workaroundmdashuse if then else and instance of
l The treat as expression can be used to change the static type of the result of an expression to a specific statictype and raises a static type error if the static type of the expression does not match the specified type It doesnot change the dynamic type or value of the expression Workaroundmdashnone
l The castable expression is useful for checking whether an atomic value can be cast to the specified typeWorkaroundmdashInstead of using the expression $x castable as T use the expression empty(data($x)) or not(empty(T($x)))
Copy Code
Copy Code
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
Constructing XML Using XQuery
XQuery constructors enable you to create XML structures within a query Constructors are available for elementsattributes processing instructions text nodes and comments
The following examples illustrate these approaches to constructing XML
Example Using constant expressions
The following query displays employment history details constructed using constant expressions
SELECT Resumequery(ltEmployer IndustryCategory=ITServicesgtltOrganizationgtABC TechnologiesltOrganizationgtltJobTitlegtSoftware EngineerltJobTitlegtltStartDategt2001-10-01ltStartDategtltEndDategt2003-05-09ltEndDategt
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]
WHERE JobCandidateID = 3
Example Using data obtained dynamically
The following query displays employment history details constructed using the results obtained from a query for acandidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmployer Organization = $EMPRESEmpOrgName gt $EMPRESEmpStartDate $EMPRESEmpEndDate $EMPRESEmpJobTitle
ltEmployergt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using constant names for computed element and attribute constructors
The following query displays the employment history of a candidate whose JobCandidateID is 3
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
element Employerattribute Organization $EMPRESEmpOrgName element StartDate string($EMPRESEmpStartDate) element EndDate string($EMPRESEmpEndDate) element JobTitle string($EMPRESEmpJobTitle)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Performing XQuery Construction vs Shaping Using FOR XML
Some applications have a requirement to generate XML from a rowset On the server XML can be generated using a FORXML clause or XQuery constructions or XML DML operations Recommendations on using FOR XML and XQueryconstructors for constructing XML are as follows
Copy Code
Copy Code
Copy Code
l If XML is to be aggregated from multiple columns and multiple rows then FOR XML is the only choice
l If a single XML instance is to be reshaped then it can be done using XQuery as well as FOR XML XQuery might befaster since the FOR XML approach will require multiple invocations of XML data type methods on the XML instance
l You can use multiple XML DML statements to construct an XML instance This approach is significantly slower thanXQuery construction
l Use the new TYPE directive available with the FOR XML clause in SQL Server 2005 to generate the result of a FORXML query as an instance of XML data type
Built-in XQuery Functions
Implementation of XQuery in SQL Server 2005 supports a subset of the built-in functions of XQuery 10 and XPath 20These functions include data accessor functions string manipulation functions aggregate functions context functionsnumeric functions Boolean functions node functions and sequence functions The following sections explore some ofthese functions
Data Accessors
You can use the data accessor functions to extract values of nodes as strings or typed values XQuery supports two typesof data accessor functions string() which extracts the string value of an item and data() which gets the typed value Ifthe node is not a text node an attribute node or an element node then the data() function throws a static error If thenode is a document node of an untyped XML instance then data() returns a string value of the document The data()function returns a static error if the node is a complex typed element
Example Using the string() function
See the Using constant names for computed element and attribute constructors example in the section Constructing XMLUsing XQuery in this paper for a query that generates the employment history of a candidate by using the string()function and computed element constructors
Example Using the data() function
The following query generates the employment history of a candidate by using the data() function and computed elementconstructors
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) gt 35return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
String Manipulation
XQuery supports four string manipulation functions
l concat() Helps concatenate two or more strings
l contains() Helps determine whether or not a string specified as the first operand contains another string specifiedas the second operand The length of the search string is limited to 4000 Unicode characters
l substring() Helps extract portion of a string from another string known as source string
l string-length() Helps calculate the length of a string
The current release of SQL Server 2005 supports only the Unicode codepoint collation
Example Using the concat() and substring() functions
The following query generates the employment history of a candidate by concatenating the values of start date enddate organization name and job title
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmploymentgtconcat( substring(string($EMPRESEmpStartDate)110) to
substring(string($EMPRESEmpEndDate)110) string($EMPRESEmpOrgName) string($EMPRESEmpJobTitle) )
ltEmploymentgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the contains() function
The following query demonstrates the use of the contains() function by displaying Education details for a node thatcontains the string science in the value of the element EduDegree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere contains($EDRESEduDegree Science)return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Aggregate Functions
Aggregate functions operate on a sequence of items and return the aggregate values of the sequence Aggregate functionscurrently supported in the XQuery support in SQL Server 2005 are count() min() max() avg() and sum() Thefunctions min() and max() accept only base types that support the gt operator (ie the three built-in numeric basetypes the datetime base types xsstring xsboolean and xdtuntypedAtomic) A sequence of mixed types is notsupported in these functions Furthermore xdtuntypedAtomic is treated as xsdouble
For avg() and sum() the type of the passed expression needs to be a subtype of one of the three built-in numeric basetypes or untypedAtomic (but not a mixture xdtuntypedAtomic is treated as xsdouble)
The count() function returns the number of items in a sequence
Example Using the count() function
The following query displays the count of employment education and address elements present in the documentusing the count() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeltEmploymentgtElement count is count(RESResumeRESAddress) ltEmploymentgtltEducationgtElement count is count(RESResumeRESEducation) ltEducationgtltAddressgtElement count is count(RESResumeRESAddress) ltAddressgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the min() function
The following query displays the education element for which the GPA value is minimum using the min() function
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = min(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the max() function
The following query displays the education element for which the GPA value is maximum using the max() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = max(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the avg() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using theavg() function
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt avg(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoNewYorkTempLow) ltAvgLowgt
ltNewYorkgtltBostongt
ltAvgHighgt avg(WeatherInfoBostonTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Example Using the sum() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using the
Copy Code
Copy Code
Copy Code
sum() and count() functions
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt sum(WeatherInfoNewYorkTempHigh) div count
(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt sum(WeatherInfoNewYorkTempLow) div count
(WeatherInfoNewYorkTempLow) ltAvgLowgtltNewYorkgtltBostongt
ltAvgHighgt sum(WeatherInfoBostonTempHigh) div count(WeatherInfoBostonTempHigh) ltAvgHighgt
ltAvgLowgt sum(WeatherInfoBostonTempLow) div count(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Context Functions
You can use the context functions to obtain the contextual properties of a context item SQL Server 2005 implements twocontext functionsmdashlast() and position() The last() function can be used to determine the number of items in asequence and the position() function can be used to obtain the position of a context item Both the last() and position() functions without an argument can only be used in the context of a context-dependent predicate (ie inside []) in SQLServer 2005
Example Using the last() function
The following query retrieves the last address element for a candidate using the last() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[last()]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the position() function
The following query retrieves the first two address elements for a candidate using the position() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[position()lt=2]
) as Result
Copy Code
Copy Code
Copy Code
FROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type-Related Expressions
XQuery supports various types of expressions or operators that are based on the type information These expressions canbe classified as type assertion expressions type inspection expressions and type casting expressions These expressionsare discussed briefly in the following sections
Type Assertion Expressions
as xsTYPE clause in for statement
You can use the as clause to specify the type for the binding variable used in the for statement
When a type is declared for the binding variable binding values that are not of the declared type would result in typeerror The xsTYPE clause is not a cast expression but it serves as a type assertion
Example Using as xsTYPE clause with for statement
The following query binds the address node sequence to a variable $A which is defined as type element(RESAddress)
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A as element(RESAddress) in RESResumeRESAddressreturn
$A) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Type Inspection Expressions
instance of xsTYPE operator
The instance of operator helps identify the runtime type of an item in an XML document
Example Using instance of xsTYPE operator
The following query checks to see if the type of an address node identified by an XPath expression matches element() typeor not
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] instance of element() )then
ltResultgtSelected node is an ElementltResultgtelse
ltResultgtSelected node is not an ElementltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type Casting Expressions
Implicit Type Casting
The XQuery engine performs implicit type casting for numeric types and untypedAtomic values in expressions that containarithmetic operations or function invocations This process is known as type promotion Type promotion occurs when anexpression results in a numeric type that is incompatible with the expected numeric type Type promotion is performed bycasting the resulting expression to the required type
Example Implicit type casting
The following query performs an arithmetic operation on a decimal value and a double value In the current scenario the
Copy Code
Copy Code
values in the expression are added only after promoting the xsdecimal value to xsdouble
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(
ltResultgt xsdecimal(1055) + xsdouble(15e1) ltResultgt) as Result
Explicit Type Casting
Typed value constructors
XQuery provides constructor functions for all built-in types defined in the XML Schema specification These constructorsare useful for constructing typed values and also for casting values from one type to another XQuery also makesconstructors available for types that are defined in imported schemas
Example Using a value constructor for constructing values
The following query returns all Employment nodes for which the StartDate is greater than a value constructed usingconstructor for type xsdate
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentwhere $EMPRESEmpStartDate gt xsdate(1995-01-01)return
$EMP) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using a value constructor for typecasting
The following query selects all Education nodes where the GPA is greater than or equal to 38 for the candidate whoseJobCandidateID is 2 This query uses the value constructor for xsdecimal for typecasting the value of EduGPA fromxsstring to xsdecimal
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) ge 38return
element Educationelement Level string($EDRESEduLevel)element StartDate string($EDRESEduStartDate)element EndDate string($EDRESEduEndDate)element Degree string($EDRESEduDegree)element GPA string($EDRESEduGPA)element GPAScale string($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
cast as xsTYPE Operator
XQuery in SQL Server 2005 supports the cast as TYPE operator which is useful for performing explicit type castingExplicit type casting can also be performed using the xsTYPE() constructors which are more convenient to write thanthe cast as TYPE operator
Example Using cast as xsTYPE operator
The following query generates an XML that contains typed values of selected elements from Education node set for acandidate whose JobCandidateID is 3
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level $EDRESEduLevel cast as xsstring element StartDate $EDRESEduStartDate cast as xsdate element EndDate $EDRESEduEndDate cast as xsdate element Degree $EDRESEduDegree cast as xsstring element GPA $EDRESEduGPA cast as xsdecimal element GPAScale $EDRESEduGPAScale cast as xsdecimal
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using xsTYPE() operator
The following query generates the same results as the query in the previous example using the xsTYPE() operatorinstead of the cast as xsTYPE operator
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level xsstring($EDRESEduLevel) element StartDate xsdate($EDRESEduStartDate) element EndDate xsdate($EDRESEduEndDate) element Degree xsstring($EDRESEduDegree) element GPA xsdecimal($EDRESEduGPA) element GPAScale xsdecimal($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Accessing Relational Columns and Variables
When writing queries using XQuery it is not uncommon to have the requirement for accessing relational columns andvariables from within the query SQL Server 2005 caters to this requirement by implementing two functionsmdashsqlcolumn() and sqlvariable()
The function sqlcolumn() can be used to access non-XML columns in a relational table from within a query This functionis useful for scenarios such as aggregating information from XML and non-XML type columns of one or more tables usingthe values of non-XML columns to filter the results of an XQuery and so on The functions sqlcolumn() andsqlvariable() cannot be used with datetime CLR user-defined functions or XML
Example Using sqlcolumn() function
The following query generates an XML that contains values from the CustomerID and Name columns of non-XML datatype and values of YearOpened NumberOfEmployees AnnualSales and AnnualRevenue elements from theDemographics column
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyelement CustomerInfo
element CustomerID sqlcolumn(StoreCustomerID) element Name sqlcolumn(StoreName) element YearOpened string((STStoreSurveySTYearOpened)[1]) element NumberOfEmployees string((STStoreSurveySTNumberEmployees)[1]) element AnnualSales string((STStoreSurveySTAnnualSales)[1]) element AnnualRevenue string((STStoreSurveySTAnnualRevenue)[1])
) as Result
Copy Code
Copy Code
Copy Code
FROM [Sales][Store] StoreWHERE StoreCustomerID = 4
Example Using sqlvariable() function
The following stored procedure returns home address nodes of a specified candidate by using the value of theAddrType variable in the XQuery where clause to filter the results of the query
CREATE PROCEDURE [GetCandidateAddress]JobCandidateID [int]AddrType [varchar](20)
ASBEGIN
SET NOCOUNT ON
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $A[ RESAddrType = sqlvariable(AddrType) ]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = JobCandidateID
END
Example Using sqlvariable() function in conjunction with the exist() method of the XML data type
The following query returns resumes of candidates who hold a Bachelors degree with a major in Business
DECLARE EducationLevel varchar(20)SET EducationLevel = Bachelor
DECLARE Major varchar(20)SET Major = Business
SELECT JobCandidateID ResumeFROM [HumanResources][JobCandidate]WHERE Resumeexist (
declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[ RESEduLevel = sqlvariable(EducationLevel) and RESEduMajor
= sqlvariable(Major) ]) = 1
Non-Supported Features and Workarounds
Current implementation of XQuery in SQL Server 2005 does not support the following features
l The let clause The let clause which is a part of the FLWOR expression is useful for binding a variable to the resultsof an expression WorkaroundmdashInstead of using the let clause use an inline expression
l Range expression (to operator) A range expression can be used to construct a sequence of consecutive integersusing the to operator For example using a range expression such as (6 to 10) it is possible to construct thesequence (6 7 8 9 10) WorkaroundmdashInstead of using the to operator list all items in your sequence
l Type information Some features that are based on type system such as typeswitch treat as castable andvalidate expressions are currently not supported
l The functionality of a typeswitch expression is similar to the switch-case construct available in otherprogramming languages In a switch-case statement the branchescases are selected based on the value of theargument passed to the switch In a typeswitch expression the branches are selected based on the type of theargument passed to typeswitch Workaroundmdashuse if then else and instance of
l The treat as expression can be used to change the static type of the result of an expression to a specific statictype and raises a static type error if the static type of the expression does not match the specified type It doesnot change the dynamic type or value of the expression Workaroundmdashnone
l The castable expression is useful for checking whether an atomic value can be cast to the specified typeWorkaroundmdashInstead of using the expression $x castable as T use the expression empty(data($x)) or not(empty(T($x)))
Copy Code
Copy Code
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
l If XML is to be aggregated from multiple columns and multiple rows then FOR XML is the only choice
l If a single XML instance is to be reshaped then it can be done using XQuery as well as FOR XML XQuery might befaster since the FOR XML approach will require multiple invocations of XML data type methods on the XML instance
l You can use multiple XML DML statements to construct an XML instance This approach is significantly slower thanXQuery construction
l Use the new TYPE directive available with the FOR XML clause in SQL Server 2005 to generate the result of a FORXML query as an instance of XML data type
Built-in XQuery Functions
Implementation of XQuery in SQL Server 2005 supports a subset of the built-in functions of XQuery 10 and XPath 20These functions include data accessor functions string manipulation functions aggregate functions context functionsnumeric functions Boolean functions node functions and sequence functions The following sections explore some ofthese functions
Data Accessors
You can use the data accessor functions to extract values of nodes as strings or typed values XQuery supports two typesof data accessor functions string() which extracts the string value of an item and data() which gets the typed value Ifthe node is not a text node an attribute node or an element node then the data() function throws a static error If thenode is a document node of an untyped XML instance then data() returns a string value of the document The data()function returns a static error if the node is a complex typed element
Example Using the string() function
See the Using constant names for computed element and attribute constructors example in the section Constructing XMLUsing XQuery in this paper for a query that generates the employment history of a candidate by using the string()function and computed element constructors
Example Using the data() function
The following query generates the employment history of a candidate by using the data() function and computed elementconstructors
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) gt 35return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
String Manipulation
XQuery supports four string manipulation functions
l concat() Helps concatenate two or more strings
l contains() Helps determine whether or not a string specified as the first operand contains another string specifiedas the second operand The length of the search string is limited to 4000 Unicode characters
l substring() Helps extract portion of a string from another string known as source string
l string-length() Helps calculate the length of a string
The current release of SQL Server 2005 supports only the Unicode codepoint collation
Example Using the concat() and substring() functions
The following query generates the employment history of a candidate by concatenating the values of start date enddate organization name and job title
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmploymentgtconcat( substring(string($EMPRESEmpStartDate)110) to
substring(string($EMPRESEmpEndDate)110) string($EMPRESEmpOrgName) string($EMPRESEmpJobTitle) )
ltEmploymentgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the contains() function
The following query demonstrates the use of the contains() function by displaying Education details for a node thatcontains the string science in the value of the element EduDegree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere contains($EDRESEduDegree Science)return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Aggregate Functions
Aggregate functions operate on a sequence of items and return the aggregate values of the sequence Aggregate functionscurrently supported in the XQuery support in SQL Server 2005 are count() min() max() avg() and sum() Thefunctions min() and max() accept only base types that support the gt operator (ie the three built-in numeric basetypes the datetime base types xsstring xsboolean and xdtuntypedAtomic) A sequence of mixed types is notsupported in these functions Furthermore xdtuntypedAtomic is treated as xsdouble
For avg() and sum() the type of the passed expression needs to be a subtype of one of the three built-in numeric basetypes or untypedAtomic (but not a mixture xdtuntypedAtomic is treated as xsdouble)
The count() function returns the number of items in a sequence
Example Using the count() function
The following query displays the count of employment education and address elements present in the documentusing the count() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeltEmploymentgtElement count is count(RESResumeRESAddress) ltEmploymentgtltEducationgtElement count is count(RESResumeRESEducation) ltEducationgtltAddressgtElement count is count(RESResumeRESAddress) ltAddressgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the min() function
The following query displays the education element for which the GPA value is minimum using the min() function
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = min(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the max() function
The following query displays the education element for which the GPA value is maximum using the max() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = max(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the avg() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using theavg() function
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt avg(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoNewYorkTempLow) ltAvgLowgt
ltNewYorkgtltBostongt
ltAvgHighgt avg(WeatherInfoBostonTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Example Using the sum() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using the
Copy Code
Copy Code
Copy Code
sum() and count() functions
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt sum(WeatherInfoNewYorkTempHigh) div count
(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt sum(WeatherInfoNewYorkTempLow) div count
(WeatherInfoNewYorkTempLow) ltAvgLowgtltNewYorkgtltBostongt
ltAvgHighgt sum(WeatherInfoBostonTempHigh) div count(WeatherInfoBostonTempHigh) ltAvgHighgt
ltAvgLowgt sum(WeatherInfoBostonTempLow) div count(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Context Functions
You can use the context functions to obtain the contextual properties of a context item SQL Server 2005 implements twocontext functionsmdashlast() and position() The last() function can be used to determine the number of items in asequence and the position() function can be used to obtain the position of a context item Both the last() and position() functions without an argument can only be used in the context of a context-dependent predicate (ie inside []) in SQLServer 2005
Example Using the last() function
The following query retrieves the last address element for a candidate using the last() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[last()]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the position() function
The following query retrieves the first two address elements for a candidate using the position() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[position()lt=2]
) as Result
Copy Code
Copy Code
Copy Code
FROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type-Related Expressions
XQuery supports various types of expressions or operators that are based on the type information These expressions canbe classified as type assertion expressions type inspection expressions and type casting expressions These expressionsare discussed briefly in the following sections
Type Assertion Expressions
as xsTYPE clause in for statement
You can use the as clause to specify the type for the binding variable used in the for statement
When a type is declared for the binding variable binding values that are not of the declared type would result in typeerror The xsTYPE clause is not a cast expression but it serves as a type assertion
Example Using as xsTYPE clause with for statement
The following query binds the address node sequence to a variable $A which is defined as type element(RESAddress)
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A as element(RESAddress) in RESResumeRESAddressreturn
$A) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Type Inspection Expressions
instance of xsTYPE operator
The instance of operator helps identify the runtime type of an item in an XML document
Example Using instance of xsTYPE operator
The following query checks to see if the type of an address node identified by an XPath expression matches element() typeor not
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] instance of element() )then
ltResultgtSelected node is an ElementltResultgtelse
ltResultgtSelected node is not an ElementltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type Casting Expressions
Implicit Type Casting
The XQuery engine performs implicit type casting for numeric types and untypedAtomic values in expressions that containarithmetic operations or function invocations This process is known as type promotion Type promotion occurs when anexpression results in a numeric type that is incompatible with the expected numeric type Type promotion is performed bycasting the resulting expression to the required type
Example Implicit type casting
The following query performs an arithmetic operation on a decimal value and a double value In the current scenario the
Copy Code
Copy Code
values in the expression are added only after promoting the xsdecimal value to xsdouble
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(
ltResultgt xsdecimal(1055) + xsdouble(15e1) ltResultgt) as Result
Explicit Type Casting
Typed value constructors
XQuery provides constructor functions for all built-in types defined in the XML Schema specification These constructorsare useful for constructing typed values and also for casting values from one type to another XQuery also makesconstructors available for types that are defined in imported schemas
Example Using a value constructor for constructing values
The following query returns all Employment nodes for which the StartDate is greater than a value constructed usingconstructor for type xsdate
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentwhere $EMPRESEmpStartDate gt xsdate(1995-01-01)return
$EMP) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using a value constructor for typecasting
The following query selects all Education nodes where the GPA is greater than or equal to 38 for the candidate whoseJobCandidateID is 2 This query uses the value constructor for xsdecimal for typecasting the value of EduGPA fromxsstring to xsdecimal
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) ge 38return
element Educationelement Level string($EDRESEduLevel)element StartDate string($EDRESEduStartDate)element EndDate string($EDRESEduEndDate)element Degree string($EDRESEduDegree)element GPA string($EDRESEduGPA)element GPAScale string($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
cast as xsTYPE Operator
XQuery in SQL Server 2005 supports the cast as TYPE operator which is useful for performing explicit type castingExplicit type casting can also be performed using the xsTYPE() constructors which are more convenient to write thanthe cast as TYPE operator
Example Using cast as xsTYPE operator
The following query generates an XML that contains typed values of selected elements from Education node set for acandidate whose JobCandidateID is 3
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level $EDRESEduLevel cast as xsstring element StartDate $EDRESEduStartDate cast as xsdate element EndDate $EDRESEduEndDate cast as xsdate element Degree $EDRESEduDegree cast as xsstring element GPA $EDRESEduGPA cast as xsdecimal element GPAScale $EDRESEduGPAScale cast as xsdecimal
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using xsTYPE() operator
The following query generates the same results as the query in the previous example using the xsTYPE() operatorinstead of the cast as xsTYPE operator
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level xsstring($EDRESEduLevel) element StartDate xsdate($EDRESEduStartDate) element EndDate xsdate($EDRESEduEndDate) element Degree xsstring($EDRESEduDegree) element GPA xsdecimal($EDRESEduGPA) element GPAScale xsdecimal($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Accessing Relational Columns and Variables
When writing queries using XQuery it is not uncommon to have the requirement for accessing relational columns andvariables from within the query SQL Server 2005 caters to this requirement by implementing two functionsmdashsqlcolumn() and sqlvariable()
The function sqlcolumn() can be used to access non-XML columns in a relational table from within a query This functionis useful for scenarios such as aggregating information from XML and non-XML type columns of one or more tables usingthe values of non-XML columns to filter the results of an XQuery and so on The functions sqlcolumn() andsqlvariable() cannot be used with datetime CLR user-defined functions or XML
Example Using sqlcolumn() function
The following query generates an XML that contains values from the CustomerID and Name columns of non-XML datatype and values of YearOpened NumberOfEmployees AnnualSales and AnnualRevenue elements from theDemographics column
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyelement CustomerInfo
element CustomerID sqlcolumn(StoreCustomerID) element Name sqlcolumn(StoreName) element YearOpened string((STStoreSurveySTYearOpened)[1]) element NumberOfEmployees string((STStoreSurveySTNumberEmployees)[1]) element AnnualSales string((STStoreSurveySTAnnualSales)[1]) element AnnualRevenue string((STStoreSurveySTAnnualRevenue)[1])
) as Result
Copy Code
Copy Code
Copy Code
FROM [Sales][Store] StoreWHERE StoreCustomerID = 4
Example Using sqlvariable() function
The following stored procedure returns home address nodes of a specified candidate by using the value of theAddrType variable in the XQuery where clause to filter the results of the query
CREATE PROCEDURE [GetCandidateAddress]JobCandidateID [int]AddrType [varchar](20)
ASBEGIN
SET NOCOUNT ON
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $A[ RESAddrType = sqlvariable(AddrType) ]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = JobCandidateID
END
Example Using sqlvariable() function in conjunction with the exist() method of the XML data type
The following query returns resumes of candidates who hold a Bachelors degree with a major in Business
DECLARE EducationLevel varchar(20)SET EducationLevel = Bachelor
DECLARE Major varchar(20)SET Major = Business
SELECT JobCandidateID ResumeFROM [HumanResources][JobCandidate]WHERE Resumeexist (
declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[ RESEduLevel = sqlvariable(EducationLevel) and RESEduMajor
= sqlvariable(Major) ]) = 1
Non-Supported Features and Workarounds
Current implementation of XQuery in SQL Server 2005 does not support the following features
l The let clause The let clause which is a part of the FLWOR expression is useful for binding a variable to the resultsof an expression WorkaroundmdashInstead of using the let clause use an inline expression
l Range expression (to operator) A range expression can be used to construct a sequence of consecutive integersusing the to operator For example using a range expression such as (6 to 10) it is possible to construct thesequence (6 7 8 9 10) WorkaroundmdashInstead of using the to operator list all items in your sequence
l Type information Some features that are based on type system such as typeswitch treat as castable andvalidate expressions are currently not supported
l The functionality of a typeswitch expression is similar to the switch-case construct available in otherprogramming languages In a switch-case statement the branchescases are selected based on the value of theargument passed to the switch In a typeswitch expression the branches are selected based on the type of theargument passed to typeswitch Workaroundmdashuse if then else and instance of
l The treat as expression can be used to change the static type of the result of an expression to a specific statictype and raises a static type error if the static type of the expression does not match the specified type It doesnot change the dynamic type or value of the expression Workaroundmdashnone
l The castable expression is useful for checking whether an atomic value can be cast to the specified typeWorkaroundmdashInstead of using the expression $x castable as T use the expression empty(data($x)) or not(empty(T($x)))
Copy Code
Copy Code
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentreturn
ltEmploymentgtconcat( substring(string($EMPRESEmpStartDate)110) to
substring(string($EMPRESEmpEndDate)110) string($EMPRESEmpOrgName) string($EMPRESEmpJobTitle) )
ltEmploymentgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the contains() function
The following query demonstrates the use of the contains() function by displaying Education details for a node thatcontains the string science in the value of the element EduDegree
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere contains($EDRESEduDegree Science)return
element Educationelement Level data($EDRESEduLevel) element Degree data($EDRESEduDegree) element GPA data($EDRESEduGPA) element GPAScale data($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Aggregate Functions
Aggregate functions operate on a sequence of items and return the aggregate values of the sequence Aggregate functionscurrently supported in the XQuery support in SQL Server 2005 are count() min() max() avg() and sum() Thefunctions min() and max() accept only base types that support the gt operator (ie the three built-in numeric basetypes the datetime base types xsstring xsboolean and xdtuntypedAtomic) A sequence of mixed types is notsupported in these functions Furthermore xdtuntypedAtomic is treated as xsdouble
For avg() and sum() the type of the passed expression needs to be a subtype of one of the three built-in numeric basetypes or untypedAtomic (but not a mixture xdtuntypedAtomic is treated as xsdouble)
The count() function returns the number of items in a sequence
Example Using the count() function
The following query displays the count of employment education and address elements present in the documentusing the count() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeltEmploymentgtElement count is count(RESResumeRESAddress) ltEmploymentgtltEducationgtElement count is count(RESResumeRESEducation) ltEducationgtltAddressgtElement count is count(RESResumeRESAddress) ltAddressgt
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the min() function
The following query displays the education element for which the GPA value is minimum using the min() function
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = min(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the max() function
The following query displays the education element for which the GPA value is maximum using the max() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = max(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the avg() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using theavg() function
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt avg(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoNewYorkTempLow) ltAvgLowgt
ltNewYorkgtltBostongt
ltAvgHighgt avg(WeatherInfoBostonTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Example Using the sum() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using the
Copy Code
Copy Code
Copy Code
sum() and count() functions
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt sum(WeatherInfoNewYorkTempHigh) div count
(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt sum(WeatherInfoNewYorkTempLow) div count
(WeatherInfoNewYorkTempLow) ltAvgLowgtltNewYorkgtltBostongt
ltAvgHighgt sum(WeatherInfoBostonTempHigh) div count(WeatherInfoBostonTempHigh) ltAvgHighgt
ltAvgLowgt sum(WeatherInfoBostonTempLow) div count(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Context Functions
You can use the context functions to obtain the contextual properties of a context item SQL Server 2005 implements twocontext functionsmdashlast() and position() The last() function can be used to determine the number of items in asequence and the position() function can be used to obtain the position of a context item Both the last() and position() functions without an argument can only be used in the context of a context-dependent predicate (ie inside []) in SQLServer 2005
Example Using the last() function
The following query retrieves the last address element for a candidate using the last() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[last()]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the position() function
The following query retrieves the first two address elements for a candidate using the position() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[position()lt=2]
) as Result
Copy Code
Copy Code
Copy Code
FROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type-Related Expressions
XQuery supports various types of expressions or operators that are based on the type information These expressions canbe classified as type assertion expressions type inspection expressions and type casting expressions These expressionsare discussed briefly in the following sections
Type Assertion Expressions
as xsTYPE clause in for statement
You can use the as clause to specify the type for the binding variable used in the for statement
When a type is declared for the binding variable binding values that are not of the declared type would result in typeerror The xsTYPE clause is not a cast expression but it serves as a type assertion
Example Using as xsTYPE clause with for statement
The following query binds the address node sequence to a variable $A which is defined as type element(RESAddress)
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A as element(RESAddress) in RESResumeRESAddressreturn
$A) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Type Inspection Expressions
instance of xsTYPE operator
The instance of operator helps identify the runtime type of an item in an XML document
Example Using instance of xsTYPE operator
The following query checks to see if the type of an address node identified by an XPath expression matches element() typeor not
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] instance of element() )then
ltResultgtSelected node is an ElementltResultgtelse
ltResultgtSelected node is not an ElementltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type Casting Expressions
Implicit Type Casting
The XQuery engine performs implicit type casting for numeric types and untypedAtomic values in expressions that containarithmetic operations or function invocations This process is known as type promotion Type promotion occurs when anexpression results in a numeric type that is incompatible with the expected numeric type Type promotion is performed bycasting the resulting expression to the required type
Example Implicit type casting
The following query performs an arithmetic operation on a decimal value and a double value In the current scenario the
Copy Code
Copy Code
values in the expression are added only after promoting the xsdecimal value to xsdouble
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(
ltResultgt xsdecimal(1055) + xsdouble(15e1) ltResultgt) as Result
Explicit Type Casting
Typed value constructors
XQuery provides constructor functions for all built-in types defined in the XML Schema specification These constructorsare useful for constructing typed values and also for casting values from one type to another XQuery also makesconstructors available for types that are defined in imported schemas
Example Using a value constructor for constructing values
The following query returns all Employment nodes for which the StartDate is greater than a value constructed usingconstructor for type xsdate
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentwhere $EMPRESEmpStartDate gt xsdate(1995-01-01)return
$EMP) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using a value constructor for typecasting
The following query selects all Education nodes where the GPA is greater than or equal to 38 for the candidate whoseJobCandidateID is 2 This query uses the value constructor for xsdecimal for typecasting the value of EduGPA fromxsstring to xsdecimal
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) ge 38return
element Educationelement Level string($EDRESEduLevel)element StartDate string($EDRESEduStartDate)element EndDate string($EDRESEduEndDate)element Degree string($EDRESEduDegree)element GPA string($EDRESEduGPA)element GPAScale string($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
cast as xsTYPE Operator
XQuery in SQL Server 2005 supports the cast as TYPE operator which is useful for performing explicit type castingExplicit type casting can also be performed using the xsTYPE() constructors which are more convenient to write thanthe cast as TYPE operator
Example Using cast as xsTYPE operator
The following query generates an XML that contains typed values of selected elements from Education node set for acandidate whose JobCandidateID is 3
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level $EDRESEduLevel cast as xsstring element StartDate $EDRESEduStartDate cast as xsdate element EndDate $EDRESEduEndDate cast as xsdate element Degree $EDRESEduDegree cast as xsstring element GPA $EDRESEduGPA cast as xsdecimal element GPAScale $EDRESEduGPAScale cast as xsdecimal
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using xsTYPE() operator
The following query generates the same results as the query in the previous example using the xsTYPE() operatorinstead of the cast as xsTYPE operator
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level xsstring($EDRESEduLevel) element StartDate xsdate($EDRESEduStartDate) element EndDate xsdate($EDRESEduEndDate) element Degree xsstring($EDRESEduDegree) element GPA xsdecimal($EDRESEduGPA) element GPAScale xsdecimal($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Accessing Relational Columns and Variables
When writing queries using XQuery it is not uncommon to have the requirement for accessing relational columns andvariables from within the query SQL Server 2005 caters to this requirement by implementing two functionsmdashsqlcolumn() and sqlvariable()
The function sqlcolumn() can be used to access non-XML columns in a relational table from within a query This functionis useful for scenarios such as aggregating information from XML and non-XML type columns of one or more tables usingthe values of non-XML columns to filter the results of an XQuery and so on The functions sqlcolumn() andsqlvariable() cannot be used with datetime CLR user-defined functions or XML
Example Using sqlcolumn() function
The following query generates an XML that contains values from the CustomerID and Name columns of non-XML datatype and values of YearOpened NumberOfEmployees AnnualSales and AnnualRevenue elements from theDemographics column
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyelement CustomerInfo
element CustomerID sqlcolumn(StoreCustomerID) element Name sqlcolumn(StoreName) element YearOpened string((STStoreSurveySTYearOpened)[1]) element NumberOfEmployees string((STStoreSurveySTNumberEmployees)[1]) element AnnualSales string((STStoreSurveySTAnnualSales)[1]) element AnnualRevenue string((STStoreSurveySTAnnualRevenue)[1])
) as Result
Copy Code
Copy Code
Copy Code
FROM [Sales][Store] StoreWHERE StoreCustomerID = 4
Example Using sqlvariable() function
The following stored procedure returns home address nodes of a specified candidate by using the value of theAddrType variable in the XQuery where clause to filter the results of the query
CREATE PROCEDURE [GetCandidateAddress]JobCandidateID [int]AddrType [varchar](20)
ASBEGIN
SET NOCOUNT ON
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $A[ RESAddrType = sqlvariable(AddrType) ]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = JobCandidateID
END
Example Using sqlvariable() function in conjunction with the exist() method of the XML data type
The following query returns resumes of candidates who hold a Bachelors degree with a major in Business
DECLARE EducationLevel varchar(20)SET EducationLevel = Bachelor
DECLARE Major varchar(20)SET Major = Business
SELECT JobCandidateID ResumeFROM [HumanResources][JobCandidate]WHERE Resumeexist (
declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[ RESEduLevel = sqlvariable(EducationLevel) and RESEduMajor
= sqlvariable(Major) ]) = 1
Non-Supported Features and Workarounds
Current implementation of XQuery in SQL Server 2005 does not support the following features
l The let clause The let clause which is a part of the FLWOR expression is useful for binding a variable to the resultsof an expression WorkaroundmdashInstead of using the let clause use an inline expression
l Range expression (to operator) A range expression can be used to construct a sequence of consecutive integersusing the to operator For example using a range expression such as (6 to 10) it is possible to construct thesequence (6 7 8 9 10) WorkaroundmdashInstead of using the to operator list all items in your sequence
l Type information Some features that are based on type system such as typeswitch treat as castable andvalidate expressions are currently not supported
l The functionality of a typeswitch expression is similar to the switch-case construct available in otherprogramming languages In a switch-case statement the branchescases are selected based on the value of theargument passed to the switch In a typeswitch expression the branches are selected based on the type of theargument passed to typeswitch Workaroundmdashuse if then else and instance of
l The treat as expression can be used to change the static type of the result of an expression to a specific statictype and raises a static type error if the static type of the expression does not match the specified type It doesnot change the dynamic type or value of the expression Workaroundmdashnone
l The castable expression is useful for checking whether an atomic value can be cast to the specified typeWorkaroundmdashInstead of using the expression $x castable as T use the expression empty(data($x)) or not(empty(T($x)))
Copy Code
Copy Code
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = min(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the max() function
The following query displays the education element for which the GPA value is maximum using the max() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere $EDRESEduGPA = max(RESResumeRESEducationRESEduGPA)return$ED
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using the avg() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using theavg() function
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt avg(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoNewYorkTempLow) ltAvgLowgt
ltNewYorkgtltBostongt
ltAvgHighgt avg(WeatherInfoBostonTempHigh) ltAvgHighgtltAvgLowgt avg(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Example Using the sum() function
The following query calculates weekly average high and low temperatures for the cities of New York and Boston using the
Copy Code
Copy Code
Copy Code
sum() and count() functions
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt sum(WeatherInfoNewYorkTempHigh) div count
(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt sum(WeatherInfoNewYorkTempLow) div count
(WeatherInfoNewYorkTempLow) ltAvgLowgtltNewYorkgtltBostongt
ltAvgHighgt sum(WeatherInfoBostonTempHigh) div count(WeatherInfoBostonTempHigh) ltAvgHighgt
ltAvgLowgt sum(WeatherInfoBostonTempLow) div count(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Context Functions
You can use the context functions to obtain the contextual properties of a context item SQL Server 2005 implements twocontext functionsmdashlast() and position() The last() function can be used to determine the number of items in asequence and the position() function can be used to obtain the position of a context item Both the last() and position() functions without an argument can only be used in the context of a context-dependent predicate (ie inside []) in SQLServer 2005
Example Using the last() function
The following query retrieves the last address element for a candidate using the last() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[last()]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the position() function
The following query retrieves the first two address elements for a candidate using the position() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[position()lt=2]
) as Result
Copy Code
Copy Code
Copy Code
FROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type-Related Expressions
XQuery supports various types of expressions or operators that are based on the type information These expressions canbe classified as type assertion expressions type inspection expressions and type casting expressions These expressionsare discussed briefly in the following sections
Type Assertion Expressions
as xsTYPE clause in for statement
You can use the as clause to specify the type for the binding variable used in the for statement
When a type is declared for the binding variable binding values that are not of the declared type would result in typeerror The xsTYPE clause is not a cast expression but it serves as a type assertion
Example Using as xsTYPE clause with for statement
The following query binds the address node sequence to a variable $A which is defined as type element(RESAddress)
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A as element(RESAddress) in RESResumeRESAddressreturn
$A) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Type Inspection Expressions
instance of xsTYPE operator
The instance of operator helps identify the runtime type of an item in an XML document
Example Using instance of xsTYPE operator
The following query checks to see if the type of an address node identified by an XPath expression matches element() typeor not
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] instance of element() )then
ltResultgtSelected node is an ElementltResultgtelse
ltResultgtSelected node is not an ElementltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type Casting Expressions
Implicit Type Casting
The XQuery engine performs implicit type casting for numeric types and untypedAtomic values in expressions that containarithmetic operations or function invocations This process is known as type promotion Type promotion occurs when anexpression results in a numeric type that is incompatible with the expected numeric type Type promotion is performed bycasting the resulting expression to the required type
Example Implicit type casting
The following query performs an arithmetic operation on a decimal value and a double value In the current scenario the
Copy Code
Copy Code
values in the expression are added only after promoting the xsdecimal value to xsdouble
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(
ltResultgt xsdecimal(1055) + xsdouble(15e1) ltResultgt) as Result
Explicit Type Casting
Typed value constructors
XQuery provides constructor functions for all built-in types defined in the XML Schema specification These constructorsare useful for constructing typed values and also for casting values from one type to another XQuery also makesconstructors available for types that are defined in imported schemas
Example Using a value constructor for constructing values
The following query returns all Employment nodes for which the StartDate is greater than a value constructed usingconstructor for type xsdate
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentwhere $EMPRESEmpStartDate gt xsdate(1995-01-01)return
$EMP) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using a value constructor for typecasting
The following query selects all Education nodes where the GPA is greater than or equal to 38 for the candidate whoseJobCandidateID is 2 This query uses the value constructor for xsdecimal for typecasting the value of EduGPA fromxsstring to xsdecimal
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) ge 38return
element Educationelement Level string($EDRESEduLevel)element StartDate string($EDRESEduStartDate)element EndDate string($EDRESEduEndDate)element Degree string($EDRESEduDegree)element GPA string($EDRESEduGPA)element GPAScale string($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
cast as xsTYPE Operator
XQuery in SQL Server 2005 supports the cast as TYPE operator which is useful for performing explicit type castingExplicit type casting can also be performed using the xsTYPE() constructors which are more convenient to write thanthe cast as TYPE operator
Example Using cast as xsTYPE operator
The following query generates an XML that contains typed values of selected elements from Education node set for acandidate whose JobCandidateID is 3
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level $EDRESEduLevel cast as xsstring element StartDate $EDRESEduStartDate cast as xsdate element EndDate $EDRESEduEndDate cast as xsdate element Degree $EDRESEduDegree cast as xsstring element GPA $EDRESEduGPA cast as xsdecimal element GPAScale $EDRESEduGPAScale cast as xsdecimal
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using xsTYPE() operator
The following query generates the same results as the query in the previous example using the xsTYPE() operatorinstead of the cast as xsTYPE operator
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level xsstring($EDRESEduLevel) element StartDate xsdate($EDRESEduStartDate) element EndDate xsdate($EDRESEduEndDate) element Degree xsstring($EDRESEduDegree) element GPA xsdecimal($EDRESEduGPA) element GPAScale xsdecimal($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Accessing Relational Columns and Variables
When writing queries using XQuery it is not uncommon to have the requirement for accessing relational columns andvariables from within the query SQL Server 2005 caters to this requirement by implementing two functionsmdashsqlcolumn() and sqlvariable()
The function sqlcolumn() can be used to access non-XML columns in a relational table from within a query This functionis useful for scenarios such as aggregating information from XML and non-XML type columns of one or more tables usingthe values of non-XML columns to filter the results of an XQuery and so on The functions sqlcolumn() andsqlvariable() cannot be used with datetime CLR user-defined functions or XML
Example Using sqlcolumn() function
The following query generates an XML that contains values from the CustomerID and Name columns of non-XML datatype and values of YearOpened NumberOfEmployees AnnualSales and AnnualRevenue elements from theDemographics column
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyelement CustomerInfo
element CustomerID sqlcolumn(StoreCustomerID) element Name sqlcolumn(StoreName) element YearOpened string((STStoreSurveySTYearOpened)[1]) element NumberOfEmployees string((STStoreSurveySTNumberEmployees)[1]) element AnnualSales string((STStoreSurveySTAnnualSales)[1]) element AnnualRevenue string((STStoreSurveySTAnnualRevenue)[1])
) as Result
Copy Code
Copy Code
Copy Code
FROM [Sales][Store] StoreWHERE StoreCustomerID = 4
Example Using sqlvariable() function
The following stored procedure returns home address nodes of a specified candidate by using the value of theAddrType variable in the XQuery where clause to filter the results of the query
CREATE PROCEDURE [GetCandidateAddress]JobCandidateID [int]AddrType [varchar](20)
ASBEGIN
SET NOCOUNT ON
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $A[ RESAddrType = sqlvariable(AddrType) ]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = JobCandidateID
END
Example Using sqlvariable() function in conjunction with the exist() method of the XML data type
The following query returns resumes of candidates who hold a Bachelors degree with a major in Business
DECLARE EducationLevel varchar(20)SET EducationLevel = Bachelor
DECLARE Major varchar(20)SET Major = Business
SELECT JobCandidateID ResumeFROM [HumanResources][JobCandidate]WHERE Resumeexist (
declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[ RESEduLevel = sqlvariable(EducationLevel) and RESEduMajor
= sqlvariable(Major) ]) = 1
Non-Supported Features and Workarounds
Current implementation of XQuery in SQL Server 2005 does not support the following features
l The let clause The let clause which is a part of the FLWOR expression is useful for binding a variable to the resultsof an expression WorkaroundmdashInstead of using the let clause use an inline expression
l Range expression (to operator) A range expression can be used to construct a sequence of consecutive integersusing the to operator For example using a range expression such as (6 to 10) it is possible to construct thesequence (6 7 8 9 10) WorkaroundmdashInstead of using the to operator list all items in your sequence
l Type information Some features that are based on type system such as typeswitch treat as castable andvalidate expressions are currently not supported
l The functionality of a typeswitch expression is similar to the switch-case construct available in otherprogramming languages In a switch-case statement the branchescases are selected based on the value of theargument passed to the switch In a typeswitch expression the branches are selected based on the type of theargument passed to typeswitch Workaroundmdashuse if then else and instance of
l The treat as expression can be used to change the static type of the result of an expression to a specific statictype and raises a static type error if the static type of the expression does not match the specified type It doesnot change the dynamic type or value of the expression Workaroundmdashnone
l The castable expression is useful for checking whether an atomic value can be cast to the specified typeWorkaroundmdashInstead of using the expression $x castable as T use the expression empty(data($x)) or not(empty(T($x)))
Copy Code
Copy Code
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
sum() and count() functions
DECLARE Weather xmlSET Weather = ltWeatherInfogt
ltNewYorkgtltTemp Date=2004-11-01 High=55 Low=45 gtltTemp Date=2004-11-02 High=58 Low=42 gtltTemp Date=2004-11-03 High=60 Low=40 gtltTemp Date=2004-11-04 High=51 Low=47 gtltTemp Date=2004-11-05 High=54 Low=41 gtltTemp Date=2004-11-06 High=55 Low=43 gtltTemp Date=2004-11-07 High=58 Low=47 gt
ltNewYorkgtltBostongt
ltTemp Date=2004-11-01 High=53 Low=45 gtltTemp Date=2004-11-02 High=56 Low=42 gtltTemp Date=2004-11-03 High=54 Low=41 gtltTemp Date=2004-11-04 High=52 Low=45 gtltTemp Date=2004-11-05 High=52 Low=36 gtltTemp Date=2004-11-06 High=54 Low=41 gtltTemp Date=2004-11-07 High=56 Low=44 gt
ltBostongtltWeatherInfogt
SELECT Weatherquery(ltWeatherInfogt
ltNewYorkgtltAvgHighgt sum(WeatherInfoNewYorkTempHigh) div count
(WeatherInfoNewYorkTempHigh) ltAvgHighgtltAvgLowgt sum(WeatherInfoNewYorkTempLow) div count
(WeatherInfoNewYorkTempLow) ltAvgLowgtltNewYorkgtltBostongt
ltAvgHighgt sum(WeatherInfoBostonTempHigh) div count(WeatherInfoBostonTempHigh) ltAvgHighgt
ltAvgLowgt sum(WeatherInfoBostonTempLow) div count(WeatherInfoBostonTempLow) ltAvgLowgt
ltBostongtltWeatherInfogt
) as Result
Context Functions
You can use the context functions to obtain the contextual properties of a context item SQL Server 2005 implements twocontext functionsmdashlast() and position() The last() function can be used to determine the number of items in asequence and the position() function can be used to obtain the position of a context item Both the last() and position() functions without an argument can only be used in the context of a context-dependent predicate (ie inside []) in SQLServer 2005
Example Using the last() function
The following query retrieves the last address element for a candidate using the last() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[last()]
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using the position() function
The following query retrieves the first two address elements for a candidate using the position() function
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESAddress[position()lt=2]
) as Result
Copy Code
Copy Code
Copy Code
FROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type-Related Expressions
XQuery supports various types of expressions or operators that are based on the type information These expressions canbe classified as type assertion expressions type inspection expressions and type casting expressions These expressionsare discussed briefly in the following sections
Type Assertion Expressions
as xsTYPE clause in for statement
You can use the as clause to specify the type for the binding variable used in the for statement
When a type is declared for the binding variable binding values that are not of the declared type would result in typeerror The xsTYPE clause is not a cast expression but it serves as a type assertion
Example Using as xsTYPE clause with for statement
The following query binds the address node sequence to a variable $A which is defined as type element(RESAddress)
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A as element(RESAddress) in RESResumeRESAddressreturn
$A) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Type Inspection Expressions
instance of xsTYPE operator
The instance of operator helps identify the runtime type of an item in an XML document
Example Using instance of xsTYPE operator
The following query checks to see if the type of an address node identified by an XPath expression matches element() typeor not
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] instance of element() )then
ltResultgtSelected node is an ElementltResultgtelse
ltResultgtSelected node is not an ElementltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type Casting Expressions
Implicit Type Casting
The XQuery engine performs implicit type casting for numeric types and untypedAtomic values in expressions that containarithmetic operations or function invocations This process is known as type promotion Type promotion occurs when anexpression results in a numeric type that is incompatible with the expected numeric type Type promotion is performed bycasting the resulting expression to the required type
Example Implicit type casting
The following query performs an arithmetic operation on a decimal value and a double value In the current scenario the
Copy Code
Copy Code
values in the expression are added only after promoting the xsdecimal value to xsdouble
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(
ltResultgt xsdecimal(1055) + xsdouble(15e1) ltResultgt) as Result
Explicit Type Casting
Typed value constructors
XQuery provides constructor functions for all built-in types defined in the XML Schema specification These constructorsare useful for constructing typed values and also for casting values from one type to another XQuery also makesconstructors available for types that are defined in imported schemas
Example Using a value constructor for constructing values
The following query returns all Employment nodes for which the StartDate is greater than a value constructed usingconstructor for type xsdate
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentwhere $EMPRESEmpStartDate gt xsdate(1995-01-01)return
$EMP) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using a value constructor for typecasting
The following query selects all Education nodes where the GPA is greater than or equal to 38 for the candidate whoseJobCandidateID is 2 This query uses the value constructor for xsdecimal for typecasting the value of EduGPA fromxsstring to xsdecimal
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) ge 38return
element Educationelement Level string($EDRESEduLevel)element StartDate string($EDRESEduStartDate)element EndDate string($EDRESEduEndDate)element Degree string($EDRESEduDegree)element GPA string($EDRESEduGPA)element GPAScale string($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
cast as xsTYPE Operator
XQuery in SQL Server 2005 supports the cast as TYPE operator which is useful for performing explicit type castingExplicit type casting can also be performed using the xsTYPE() constructors which are more convenient to write thanthe cast as TYPE operator
Example Using cast as xsTYPE operator
The following query generates an XML that contains typed values of selected elements from Education node set for acandidate whose JobCandidateID is 3
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level $EDRESEduLevel cast as xsstring element StartDate $EDRESEduStartDate cast as xsdate element EndDate $EDRESEduEndDate cast as xsdate element Degree $EDRESEduDegree cast as xsstring element GPA $EDRESEduGPA cast as xsdecimal element GPAScale $EDRESEduGPAScale cast as xsdecimal
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using xsTYPE() operator
The following query generates the same results as the query in the previous example using the xsTYPE() operatorinstead of the cast as xsTYPE operator
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level xsstring($EDRESEduLevel) element StartDate xsdate($EDRESEduStartDate) element EndDate xsdate($EDRESEduEndDate) element Degree xsstring($EDRESEduDegree) element GPA xsdecimal($EDRESEduGPA) element GPAScale xsdecimal($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Accessing Relational Columns and Variables
When writing queries using XQuery it is not uncommon to have the requirement for accessing relational columns andvariables from within the query SQL Server 2005 caters to this requirement by implementing two functionsmdashsqlcolumn() and sqlvariable()
The function sqlcolumn() can be used to access non-XML columns in a relational table from within a query This functionis useful for scenarios such as aggregating information from XML and non-XML type columns of one or more tables usingthe values of non-XML columns to filter the results of an XQuery and so on The functions sqlcolumn() andsqlvariable() cannot be used with datetime CLR user-defined functions or XML
Example Using sqlcolumn() function
The following query generates an XML that contains values from the CustomerID and Name columns of non-XML datatype and values of YearOpened NumberOfEmployees AnnualSales and AnnualRevenue elements from theDemographics column
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyelement CustomerInfo
element CustomerID sqlcolumn(StoreCustomerID) element Name sqlcolumn(StoreName) element YearOpened string((STStoreSurveySTYearOpened)[1]) element NumberOfEmployees string((STStoreSurveySTNumberEmployees)[1]) element AnnualSales string((STStoreSurveySTAnnualSales)[1]) element AnnualRevenue string((STStoreSurveySTAnnualRevenue)[1])
) as Result
Copy Code
Copy Code
Copy Code
FROM [Sales][Store] StoreWHERE StoreCustomerID = 4
Example Using sqlvariable() function
The following stored procedure returns home address nodes of a specified candidate by using the value of theAddrType variable in the XQuery where clause to filter the results of the query
CREATE PROCEDURE [GetCandidateAddress]JobCandidateID [int]AddrType [varchar](20)
ASBEGIN
SET NOCOUNT ON
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $A[ RESAddrType = sqlvariable(AddrType) ]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = JobCandidateID
END
Example Using sqlvariable() function in conjunction with the exist() method of the XML data type
The following query returns resumes of candidates who hold a Bachelors degree with a major in Business
DECLARE EducationLevel varchar(20)SET EducationLevel = Bachelor
DECLARE Major varchar(20)SET Major = Business
SELECT JobCandidateID ResumeFROM [HumanResources][JobCandidate]WHERE Resumeexist (
declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[ RESEduLevel = sqlvariable(EducationLevel) and RESEduMajor
= sqlvariable(Major) ]) = 1
Non-Supported Features and Workarounds
Current implementation of XQuery in SQL Server 2005 does not support the following features
l The let clause The let clause which is a part of the FLWOR expression is useful for binding a variable to the resultsof an expression WorkaroundmdashInstead of using the let clause use an inline expression
l Range expression (to operator) A range expression can be used to construct a sequence of consecutive integersusing the to operator For example using a range expression such as (6 to 10) it is possible to construct thesequence (6 7 8 9 10) WorkaroundmdashInstead of using the to operator list all items in your sequence
l Type information Some features that are based on type system such as typeswitch treat as castable andvalidate expressions are currently not supported
l The functionality of a typeswitch expression is similar to the switch-case construct available in otherprogramming languages In a switch-case statement the branchescases are selected based on the value of theargument passed to the switch In a typeswitch expression the branches are selected based on the type of theargument passed to typeswitch Workaroundmdashuse if then else and instance of
l The treat as expression can be used to change the static type of the result of an expression to a specific statictype and raises a static type error if the static type of the expression does not match the specified type It doesnot change the dynamic type or value of the expression Workaroundmdashnone
l The castable expression is useful for checking whether an atomic value can be cast to the specified typeWorkaroundmdashInstead of using the expression $x castable as T use the expression empty(data($x)) or not(empty(T($x)))
Copy Code
Copy Code
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
FROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type-Related Expressions
XQuery supports various types of expressions or operators that are based on the type information These expressions canbe classified as type assertion expressions type inspection expressions and type casting expressions These expressionsare discussed briefly in the following sections
Type Assertion Expressions
as xsTYPE clause in for statement
You can use the as clause to specify the type for the binding variable used in the for statement
When a type is declared for the binding variable binding values that are not of the declared type would result in typeerror The xsTYPE clause is not a cast expression but it serves as a type assertion
Example Using as xsTYPE clause with for statement
The following query binds the address node sequence to a variable $A which is defined as type element(RESAddress)
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A as element(RESAddress) in RESResumeRESAddressreturn
$A) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Type Inspection Expressions
instance of xsTYPE operator
The instance of operator helps identify the runtime type of an item in an XML document
Example Using instance of xsTYPE operator
The following query checks to see if the type of an address node identified by an XPath expression matches element() typeor not
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeif ( (RESResumeRESAddress)[1] instance of element() )then
ltResultgtSelected node is an ElementltResultgtelse
ltResultgtSelected node is not an ElementltResultgt) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Type Casting Expressions
Implicit Type Casting
The XQuery engine performs implicit type casting for numeric types and untypedAtomic values in expressions that containarithmetic operations or function invocations This process is known as type promotion Type promotion occurs when anexpression results in a numeric type that is incompatible with the expected numeric type Type promotion is performed bycasting the resulting expression to the required type
Example Implicit type casting
The following query performs an arithmetic operation on a decimal value and a double value In the current scenario the
Copy Code
Copy Code
values in the expression are added only after promoting the xsdecimal value to xsdouble
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(
ltResultgt xsdecimal(1055) + xsdouble(15e1) ltResultgt) as Result
Explicit Type Casting
Typed value constructors
XQuery provides constructor functions for all built-in types defined in the XML Schema specification These constructorsare useful for constructing typed values and also for casting values from one type to another XQuery also makesconstructors available for types that are defined in imported schemas
Example Using a value constructor for constructing values
The following query returns all Employment nodes for which the StartDate is greater than a value constructed usingconstructor for type xsdate
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentwhere $EMPRESEmpStartDate gt xsdate(1995-01-01)return
$EMP) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using a value constructor for typecasting
The following query selects all Education nodes where the GPA is greater than or equal to 38 for the candidate whoseJobCandidateID is 2 This query uses the value constructor for xsdecimal for typecasting the value of EduGPA fromxsstring to xsdecimal
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) ge 38return
element Educationelement Level string($EDRESEduLevel)element StartDate string($EDRESEduStartDate)element EndDate string($EDRESEduEndDate)element Degree string($EDRESEduDegree)element GPA string($EDRESEduGPA)element GPAScale string($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
cast as xsTYPE Operator
XQuery in SQL Server 2005 supports the cast as TYPE operator which is useful for performing explicit type castingExplicit type casting can also be performed using the xsTYPE() constructors which are more convenient to write thanthe cast as TYPE operator
Example Using cast as xsTYPE operator
The following query generates an XML that contains typed values of selected elements from Education node set for acandidate whose JobCandidateID is 3
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level $EDRESEduLevel cast as xsstring element StartDate $EDRESEduStartDate cast as xsdate element EndDate $EDRESEduEndDate cast as xsdate element Degree $EDRESEduDegree cast as xsstring element GPA $EDRESEduGPA cast as xsdecimal element GPAScale $EDRESEduGPAScale cast as xsdecimal
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using xsTYPE() operator
The following query generates the same results as the query in the previous example using the xsTYPE() operatorinstead of the cast as xsTYPE operator
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level xsstring($EDRESEduLevel) element StartDate xsdate($EDRESEduStartDate) element EndDate xsdate($EDRESEduEndDate) element Degree xsstring($EDRESEduDegree) element GPA xsdecimal($EDRESEduGPA) element GPAScale xsdecimal($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Accessing Relational Columns and Variables
When writing queries using XQuery it is not uncommon to have the requirement for accessing relational columns andvariables from within the query SQL Server 2005 caters to this requirement by implementing two functionsmdashsqlcolumn() and sqlvariable()
The function sqlcolumn() can be used to access non-XML columns in a relational table from within a query This functionis useful for scenarios such as aggregating information from XML and non-XML type columns of one or more tables usingthe values of non-XML columns to filter the results of an XQuery and so on The functions sqlcolumn() andsqlvariable() cannot be used with datetime CLR user-defined functions or XML
Example Using sqlcolumn() function
The following query generates an XML that contains values from the CustomerID and Name columns of non-XML datatype and values of YearOpened NumberOfEmployees AnnualSales and AnnualRevenue elements from theDemographics column
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyelement CustomerInfo
element CustomerID sqlcolumn(StoreCustomerID) element Name sqlcolumn(StoreName) element YearOpened string((STStoreSurveySTYearOpened)[1]) element NumberOfEmployees string((STStoreSurveySTNumberEmployees)[1]) element AnnualSales string((STStoreSurveySTAnnualSales)[1]) element AnnualRevenue string((STStoreSurveySTAnnualRevenue)[1])
) as Result
Copy Code
Copy Code
Copy Code
FROM [Sales][Store] StoreWHERE StoreCustomerID = 4
Example Using sqlvariable() function
The following stored procedure returns home address nodes of a specified candidate by using the value of theAddrType variable in the XQuery where clause to filter the results of the query
CREATE PROCEDURE [GetCandidateAddress]JobCandidateID [int]AddrType [varchar](20)
ASBEGIN
SET NOCOUNT ON
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $A[ RESAddrType = sqlvariable(AddrType) ]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = JobCandidateID
END
Example Using sqlvariable() function in conjunction with the exist() method of the XML data type
The following query returns resumes of candidates who hold a Bachelors degree with a major in Business
DECLARE EducationLevel varchar(20)SET EducationLevel = Bachelor
DECLARE Major varchar(20)SET Major = Business
SELECT JobCandidateID ResumeFROM [HumanResources][JobCandidate]WHERE Resumeexist (
declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[ RESEduLevel = sqlvariable(EducationLevel) and RESEduMajor
= sqlvariable(Major) ]) = 1
Non-Supported Features and Workarounds
Current implementation of XQuery in SQL Server 2005 does not support the following features
l The let clause The let clause which is a part of the FLWOR expression is useful for binding a variable to the resultsof an expression WorkaroundmdashInstead of using the let clause use an inline expression
l Range expression (to operator) A range expression can be used to construct a sequence of consecutive integersusing the to operator For example using a range expression such as (6 to 10) it is possible to construct thesequence (6 7 8 9 10) WorkaroundmdashInstead of using the to operator list all items in your sequence
l Type information Some features that are based on type system such as typeswitch treat as castable andvalidate expressions are currently not supported
l The functionality of a typeswitch expression is similar to the switch-case construct available in otherprogramming languages In a switch-case statement the branchescases are selected based on the value of theargument passed to the switch In a typeswitch expression the branches are selected based on the type of theargument passed to typeswitch Workaroundmdashuse if then else and instance of
l The treat as expression can be used to change the static type of the result of an expression to a specific statictype and raises a static type error if the static type of the expression does not match the specified type It doesnot change the dynamic type or value of the expression Workaroundmdashnone
l The castable expression is useful for checking whether an atomic value can be cast to the specified typeWorkaroundmdashInstead of using the expression $x castable as T use the expression empty(data($x)) or not(empty(T($x)))
Copy Code
Copy Code
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
values in the expression are added only after promoting the xsdecimal value to xsdouble
DECLARE Result xmlSET Result = ltResult gtSELECT Resultquery(
ltResultgt xsdecimal(1055) + xsdouble(15e1) ltResultgt) as Result
Explicit Type Casting
Typed value constructors
XQuery provides constructor functions for all built-in types defined in the XML Schema specification These constructorsare useful for constructing typed values and also for casting values from one type to another XQuery also makesconstructors available for types that are defined in imported schemas
Example Using a value constructor for constructing values
The following query returns all Employment nodes for which the StartDate is greater than a value constructed usingconstructor for type xsdate
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $EMP in RESResumeRESEmploymentwhere $EMPRESEmpStartDate gt xsdate(1995-01-01)return
$EMP) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 3
Example Using a value constructor for typecasting
The following query selects all Education nodes where the GPA is greater than or equal to 38 for the candidate whoseJobCandidateID is 2 This query uses the value constructor for xsdecimal for typecasting the value of EduGPA fromxsstring to xsdecimal
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationwhere xsdecimal( data($EDRESEduGPA) ) ge 38return
element Educationelement Level string($EDRESEduLevel)element StartDate string($EDRESEduStartDate)element EndDate string($EDRESEduEndDate)element Degree string($EDRESEduDegree)element GPA string($EDRESEduGPA)element GPAScale string($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
cast as xsTYPE Operator
XQuery in SQL Server 2005 supports the cast as TYPE operator which is useful for performing explicit type castingExplicit type casting can also be performed using the xsTYPE() constructors which are more convenient to write thanthe cast as TYPE operator
Example Using cast as xsTYPE operator
The following query generates an XML that contains typed values of selected elements from Education node set for acandidate whose JobCandidateID is 3
Copy Code
Copy Code
Copy Code
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level $EDRESEduLevel cast as xsstring element StartDate $EDRESEduStartDate cast as xsdate element EndDate $EDRESEduEndDate cast as xsdate element Degree $EDRESEduDegree cast as xsstring element GPA $EDRESEduGPA cast as xsdecimal element GPAScale $EDRESEduGPAScale cast as xsdecimal
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using xsTYPE() operator
The following query generates the same results as the query in the previous example using the xsTYPE() operatorinstead of the cast as xsTYPE operator
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level xsstring($EDRESEduLevel) element StartDate xsdate($EDRESEduStartDate) element EndDate xsdate($EDRESEduEndDate) element Degree xsstring($EDRESEduDegree) element GPA xsdecimal($EDRESEduGPA) element GPAScale xsdecimal($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Accessing Relational Columns and Variables
When writing queries using XQuery it is not uncommon to have the requirement for accessing relational columns andvariables from within the query SQL Server 2005 caters to this requirement by implementing two functionsmdashsqlcolumn() and sqlvariable()
The function sqlcolumn() can be used to access non-XML columns in a relational table from within a query This functionis useful for scenarios such as aggregating information from XML and non-XML type columns of one or more tables usingthe values of non-XML columns to filter the results of an XQuery and so on The functions sqlcolumn() andsqlvariable() cannot be used with datetime CLR user-defined functions or XML
Example Using sqlcolumn() function
The following query generates an XML that contains values from the CustomerID and Name columns of non-XML datatype and values of YearOpened NumberOfEmployees AnnualSales and AnnualRevenue elements from theDemographics column
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyelement CustomerInfo
element CustomerID sqlcolumn(StoreCustomerID) element Name sqlcolumn(StoreName) element YearOpened string((STStoreSurveySTYearOpened)[1]) element NumberOfEmployees string((STStoreSurveySTNumberEmployees)[1]) element AnnualSales string((STStoreSurveySTAnnualSales)[1]) element AnnualRevenue string((STStoreSurveySTAnnualRevenue)[1])
) as Result
Copy Code
Copy Code
Copy Code
FROM [Sales][Store] StoreWHERE StoreCustomerID = 4
Example Using sqlvariable() function
The following stored procedure returns home address nodes of a specified candidate by using the value of theAddrType variable in the XQuery where clause to filter the results of the query
CREATE PROCEDURE [GetCandidateAddress]JobCandidateID [int]AddrType [varchar](20)
ASBEGIN
SET NOCOUNT ON
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $A[ RESAddrType = sqlvariable(AddrType) ]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = JobCandidateID
END
Example Using sqlvariable() function in conjunction with the exist() method of the XML data type
The following query returns resumes of candidates who hold a Bachelors degree with a major in Business
DECLARE EducationLevel varchar(20)SET EducationLevel = Bachelor
DECLARE Major varchar(20)SET Major = Business
SELECT JobCandidateID ResumeFROM [HumanResources][JobCandidate]WHERE Resumeexist (
declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[ RESEduLevel = sqlvariable(EducationLevel) and RESEduMajor
= sqlvariable(Major) ]) = 1
Non-Supported Features and Workarounds
Current implementation of XQuery in SQL Server 2005 does not support the following features
l The let clause The let clause which is a part of the FLWOR expression is useful for binding a variable to the resultsof an expression WorkaroundmdashInstead of using the let clause use an inline expression
l Range expression (to operator) A range expression can be used to construct a sequence of consecutive integersusing the to operator For example using a range expression such as (6 to 10) it is possible to construct thesequence (6 7 8 9 10) WorkaroundmdashInstead of using the to operator list all items in your sequence
l Type information Some features that are based on type system such as typeswitch treat as castable andvalidate expressions are currently not supported
l The functionality of a typeswitch expression is similar to the switch-case construct available in otherprogramming languages In a switch-case statement the branchescases are selected based on the value of theargument passed to the switch In a typeswitch expression the branches are selected based on the type of theargument passed to typeswitch Workaroundmdashuse if then else and instance of
l The treat as expression can be used to change the static type of the result of an expression to a specific statictype and raises a static type error if the static type of the expression does not match the specified type It doesnot change the dynamic type or value of the expression Workaroundmdashnone
l The castable expression is useful for checking whether an atomic value can be cast to the specified typeWorkaroundmdashInstead of using the expression $x castable as T use the expression empty(data($x)) or not(empty(T($x)))
Copy Code
Copy Code
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level $EDRESEduLevel cast as xsstring element StartDate $EDRESEduStartDate cast as xsdate element EndDate $EDRESEduEndDate cast as xsdate element Degree $EDRESEduDegree cast as xsstring element GPA $EDRESEduGPA cast as xsdecimal element GPAScale $EDRESEduGPAScale cast as xsdecimal
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Example Using xsTYPE() operator
The following query generates the same results as the query in the previous example using the xsTYPE() operatorinstead of the cast as xsTYPE operator
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $ED in RESResumeRESEducationreturn
element Educationelement Level xsstring($EDRESEduLevel) element StartDate xsdate($EDRESEduStartDate) element EndDate xsdate($EDRESEduEndDate) element Degree xsstring($EDRESEduDegree) element GPA xsdecimal($EDRESEduGPA) element GPAScale xsdecimal($EDRESEduGPAScale)
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = 2
Accessing Relational Columns and Variables
When writing queries using XQuery it is not uncommon to have the requirement for accessing relational columns andvariables from within the query SQL Server 2005 caters to this requirement by implementing two functionsmdashsqlcolumn() and sqlvariable()
The function sqlcolumn() can be used to access non-XML columns in a relational table from within a query This functionis useful for scenarios such as aggregating information from XML and non-XML type columns of one or more tables usingthe values of non-XML columns to filter the results of an XQuery and so on The functions sqlcolumn() andsqlvariable() cannot be used with datetime CLR user-defined functions or XML
Example Using sqlcolumn() function
The following query generates an XML that contains values from the CustomerID and Name columns of non-XML datatype and values of YearOpened NumberOfEmployees AnnualSales and AnnualRevenue elements from theDemographics column
SELECT Demographicsquery(declare namespace ST=httpschemasmicrosoftcomsqlserver200407adventure-
worksStoreSurveyelement CustomerInfo
element CustomerID sqlcolumn(StoreCustomerID) element Name sqlcolumn(StoreName) element YearOpened string((STStoreSurveySTYearOpened)[1]) element NumberOfEmployees string((STStoreSurveySTNumberEmployees)[1]) element AnnualSales string((STStoreSurveySTAnnualSales)[1]) element AnnualRevenue string((STStoreSurveySTAnnualRevenue)[1])
) as Result
Copy Code
Copy Code
Copy Code
FROM [Sales][Store] StoreWHERE StoreCustomerID = 4
Example Using sqlvariable() function
The following stored procedure returns home address nodes of a specified candidate by using the value of theAddrType variable in the XQuery where clause to filter the results of the query
CREATE PROCEDURE [GetCandidateAddress]JobCandidateID [int]AddrType [varchar](20)
ASBEGIN
SET NOCOUNT ON
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $A[ RESAddrType = sqlvariable(AddrType) ]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = JobCandidateID
END
Example Using sqlvariable() function in conjunction with the exist() method of the XML data type
The following query returns resumes of candidates who hold a Bachelors degree with a major in Business
DECLARE EducationLevel varchar(20)SET EducationLevel = Bachelor
DECLARE Major varchar(20)SET Major = Business
SELECT JobCandidateID ResumeFROM [HumanResources][JobCandidate]WHERE Resumeexist (
declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[ RESEduLevel = sqlvariable(EducationLevel) and RESEduMajor
= sqlvariable(Major) ]) = 1
Non-Supported Features and Workarounds
Current implementation of XQuery in SQL Server 2005 does not support the following features
l The let clause The let clause which is a part of the FLWOR expression is useful for binding a variable to the resultsof an expression WorkaroundmdashInstead of using the let clause use an inline expression
l Range expression (to operator) A range expression can be used to construct a sequence of consecutive integersusing the to operator For example using a range expression such as (6 to 10) it is possible to construct thesequence (6 7 8 9 10) WorkaroundmdashInstead of using the to operator list all items in your sequence
l Type information Some features that are based on type system such as typeswitch treat as castable andvalidate expressions are currently not supported
l The functionality of a typeswitch expression is similar to the switch-case construct available in otherprogramming languages In a switch-case statement the branchescases are selected based on the value of theargument passed to the switch In a typeswitch expression the branches are selected based on the type of theargument passed to typeswitch Workaroundmdashuse if then else and instance of
l The treat as expression can be used to change the static type of the result of an expression to a specific statictype and raises a static type error if the static type of the expression does not match the specified type It doesnot change the dynamic type or value of the expression Workaroundmdashnone
l The castable expression is useful for checking whether an atomic value can be cast to the specified typeWorkaroundmdashInstead of using the expression $x castable as T use the expression empty(data($x)) or not(empty(T($x)))
Copy Code
Copy Code
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
FROM [Sales][Store] StoreWHERE StoreCustomerID = 4
Example Using sqlvariable() function
The following stored procedure returns home address nodes of a specified candidate by using the value of theAddrType variable in the XQuery where clause to filter the results of the query
CREATE PROCEDURE [GetCandidateAddress]JobCandidateID [int]AddrType [varchar](20)
ASBEGIN
SET NOCOUNT ON
SELECT Resumequery(declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumefor $A in RESResumeRESAddresswhere $A[ RESAddrType = sqlvariable(AddrType) ]return$A
) as ResultFROM [HumanResources][JobCandidate]WHERE JobCandidateID = JobCandidateID
END
Example Using sqlvariable() function in conjunction with the exist() method of the XML data type
The following query returns resumes of candidates who hold a Bachelors degree with a major in Business
DECLARE EducationLevel varchar(20)SET EducationLevel = Bachelor
DECLARE Major varchar(20)SET Major = Business
SELECT JobCandidateID ResumeFROM [HumanResources][JobCandidate]WHERE Resumeexist (
declare namespace RES=httpschemasmicrosoftcomsqlserver200407adventure-worksResumeRESResumeRESEducation[ RESEduLevel = sqlvariable(EducationLevel) and RESEduMajor
= sqlvariable(Major) ]) = 1
Non-Supported Features and Workarounds
Current implementation of XQuery in SQL Server 2005 does not support the following features
l The let clause The let clause which is a part of the FLWOR expression is useful for binding a variable to the resultsof an expression WorkaroundmdashInstead of using the let clause use an inline expression
l Range expression (to operator) A range expression can be used to construct a sequence of consecutive integersusing the to operator For example using a range expression such as (6 to 10) it is possible to construct thesequence (6 7 8 9 10) WorkaroundmdashInstead of using the to operator list all items in your sequence
l Type information Some features that are based on type system such as typeswitch treat as castable andvalidate expressions are currently not supported
l The functionality of a typeswitch expression is similar to the switch-case construct available in otherprogramming languages In a switch-case statement the branchescases are selected based on the value of theargument passed to the switch In a typeswitch expression the branches are selected based on the type of theargument passed to typeswitch Workaroundmdashuse if then else and instance of
l The treat as expression can be used to change the static type of the result of an expression to a specific statictype and raises a static type error if the static type of the expression does not match the specified type It doesnot change the dynamic type or value of the expression Workaroundmdashnone
l The castable expression is useful for checking whether an atomic value can be cast to the specified typeWorkaroundmdashInstead of using the expression $x castable as T use the expression empty(data($x)) or not(empty(T($x)))
Copy Code
Copy Code
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
l The validate expression performs validation on its argument based on the schema definitions present in thecurrent scope WorkaroundmdashInstead of using the validate expression use the Transact-SQL casting to therequested schema collection
l Reusability As in other programming languages it is possible to write reusable functions known as user-definedfunctions that contain useful and complex queries In addition it is also possible to package a collection of user-defined functions as modules Queries can make use of the functions available in modules by importing the modulesModules can be imported into a query by including them in the prolog section of the query No workaround in SQLServer 2005
l Built-in functions The following built-in functions are currently not supported in SQL Server 2005 For moreinformation about these functions see XQuery 10 and XPath 20 Functions and Operators[ httpwwww3orgTRxquery-operators ] on the W3Corg Web site
l Accessors fnnode-name() fnnilled() fnbase-uri() fndocument-uri()
l Error function fnerror()
l Trace function fntrace()
l Functions on numeric values abs() round-half-to-even()
l String-handling functions codepoints-to-string() string-to-codepoints() compare() string-join() normalize-space() normalize-unicode() upper-case() lower-case() translate() escape-uri() starts-with() ends-with()substring-before() substring-after() matches() replace() tokenize()
l Functions and operators for anyURI resolve-uri()
l Functions and operators on durations dates and time years-from-duration() months-from-duration()days-from-duration() hours-from-duration() minutes-from-duration() seconds-from-duration() year-from-dateTime() month-from-dateTime() month-from-dateTime() day-from-dateTime() hours-from-dateTime()minutes-from-dateTime() seconds-from-dateTime() timezone-from-dateTime() year-from-date() month-from-date() day-from-date() timezone-from-date() hours-from-time() minutes-from-time() seconds-from-time()timezone-from-time() adjust-dateTime-to-timezone() adjust-date-to-timezone() adjust-time-to-timezone()subtract-dateTimes-yielding-yearMonthDuration() subtract-dateTimes-yielding-dayTimeDuration() subtract-dates-yielding-yearMonthDuration() subtract-dates-yielding-dayTimeDuration() Also types xdtdayTimeDurationand xdtyearMonthDuration are not supported
l Functions related to QNames resolve-QName() QName() namespace-uri-for-prefix() in-scope-prefixes()
l Functions on nodes name() lang() root() Workaroundmdashuse instead of root()
l Functions and operators on sequences fnboolean() fnindex-of() fnexists() insert-before() remove()reverse() subsequence() unordered() zero-or-one() one-or-more() exactly-one() deep-equal()two-argumentversion of id() idref() doc() collection() functions and union intersect and except operators Workaroundsmdashusenot(not()) instead of fnboolean() use not(empty()) instead of fnexists() Use either an explicit for iteration or[1] instead of zero-or-one() or exactly-one()
l Context functions current-dateTime() current-date() current-time() default-collation() implicit-timezone()
l Positional variable Positional variables can be defined as part of a FLWOR statement using the at clause and areuseful for identifying the location of an item in the result of an expression
l Order modifier The order modifier empty greatest | least specified with an order by clause is not supported
l Other features The following features are not supported
l The idiv operator
l Explicit schema import is not supported
l External variables are not supported
l Boundary white space preservation option is not supported
l Concatenation of heterogeneous sequences such as nodes and values is not supported
l No support for time zone preservation
l Accessing a text node of an element with a simple typed content is not supported
l No support for accessing xsi attributes in a typed XML data type instance
Best Practices and Guidelines
l Take advantage of type information if it is available This will provide performance improvements and the ability toperform static type checking to detect errors
l Use XQuery for property promotions if you want to extract the values of a few properties from XML data type and usethem in relational queries Frequently used properties are promoted to relational columns and indexed for betterperformance
l Use an ordinal such as [1] or explicit FLWOR to avoid static errors due to cardinality mismatch
l Use explicit casts to avoid static type errors
l Index usage Create a PATH index if you have queries with heavy use of XPath expressions Use a VALUE index whenthe XQuey query contains XPath expressions that involve searching for element or attribute values with impreciselyknown paths (eg a or b) PROPERTY index is useful when the query involves searching for all occurrences of aknown property within an XML instance
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
l Use a default namespace when most of the types referred are part of a single namespace Otherwise use a prefix
For more information on best practices see the MSDN articles XML Best Practices for Microsoft SQL Server 2005[ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ] and Performance Optimizations for the XML DataType [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
XML Data Modification
SQL Server 2005 provides support for modifying XML instances stored in the database The current version of the W3CXQuery working draft does not define a syntax for modifying XML documents In order to provide a mechanism formodifying XML documents Microsoft has developed XML Data Modification Language (DML) XML documents can bemodified using the modify method of the XML data type and specifying the modification using XML DML statements
XML DML uses the insert delete and replace value of keywords to support insert delete and update operations onXML documents Modification of a typed XML instance is subjected to validation checks according to the schemaconstraints defined on the XML data type
The following table and XML instance are used to illustrate XML DML operations
Table
CREATE TABLE [CandidateInfoXMLDataType](
[JobCandidateID] [int] IDENTITY(11) NOT NULL[Resume] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)
Sample XML Instance
ltJobCandidategtltNamegt
ltFirstNamegtMikeltFirstNamegtltMiddleNamegtltMiddleNamegtltLastNamegtChenltLastNamegt
ltNamegtltAddressgt
ltAddress1gt34 181st Place SEltAddress1gtltAddress2gtApt 3344ltAddress2gtltCitygtRedmondltCitygtltStategtWAltStategtltCountrygtUSltCountrygtltPhoneNumbergt9870909023ltPhoneNumbergt
ltAddressgtltEducationgt
ltBachelorDegreegtBSltBachelorDegreegtltMasterDegreegtMSltMasterDegreegt
ltEducationgtltSkillsgt
ltSkillgtASPNETltSkillgtltSkillgtSQLltSkillgt
ltSkillsgtltEmployementgt
ltEmployergtltOrgNamegtABC TechnologiesltOrgNamegt
ltLocationgtNY USltLocationgtltStartDategt20022000ltStartDategtltEndDategt10042004ltEndDategtltJobTitlegtProject LeaderltJobTitlegtltResponsibilitygtResponsible for designdevelopmenttesting activitiesltResponsibilitygt
ltEmployergtltEmployementgt
ltJobCandidategt
The Insert Operation
You can use the insert keyword to insert one or more nodes in an XML document The insert keyword accepts an XQueryexpression that identifies the nodes to be inserted and another XQuery expression that specifies the reference node
In addition you can include keywords such as into after and before to specify the position of new nodes in relation to
Copy Code
Copy Code
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
the reference node When you specify the into keyword new nodes are inserted as children of the reference node If youinclude the into keyword you must also specify the as first or the as last keyword to indicate the position of insertednodes with respect to the existing child nodes of the reference node You can also insert new nodes as sibling nodes afteror before the reference node by specifying the after or the before keyword
If the target expression (Expression2) does not identify a single node statically the insert operation will fail with a staticerror
Syntax
insertExpression1 (
as first | as last into | after | beforeExpression2 )
Example Inserting a skill
The following stored procedure allows the user to insert a new skill for a specified candidate This stored procedure usesthe sqlvariable() function to access a Transact-SQL variable inside the XML DML statements For details on how to bindnon-XML relational data inside XML see Accessing Relational Columns and Variables
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby enabling the user to insert multiple skill nodes with a single call to the storedprocedure
Stored procedure to insert a new skill element for a candidate CREATE PROCEDURE [InsertSkillInfo]
JobCandidateID [int]Skill [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(insert element Skill sqlvariable(Skill)as lastinto (JobCandidateSkills)[1])WHERE JobCandidateID = JobCandidateID
END
The Delete Operation
The delete keyword enables you to delete one or more nodes from an XML instance The delete keyword accepts anXQuery expression that identifies one or more nodes to be deleted from the XML document
Syntax
delete Expression
Example Deleting a skill
The following example illustrates the use of the delete keyword to delete a skill for a specified candidate
The following stored procedure is written based on the assumption that the user will pass a string value of one skill as thesecond argument to the stored procedure This stored procedure can be modified to accept an XML fragment that containsone or more skill elements thereby allowing the user to delete multiple skill nodes with a single invocation of the storedprocedure
Stored procedure to delete a specified skill element for a candidate CREATE PROCEDURE [DeleteSkillInfo]
JobCandidateID [int]
Copy Code
Copy Code
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
Skill [varchar](200)ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(delete (JobCandidateSkillsSkill[=sqlvariable(Skill)]))WHERE JobCandidateID = JobCandidateID
END
This stored procedure can easily be modified to accept an XML fragment which contains one or more skill elementsthereby allowing the user to delete multiple skill nodes with a single invocation of stored procedure
The Update Operation
The replace value of keyword enables you to modify the value of an existing node To modify the value of an existingnode you have to specify an XQuery expression that identifies the node whose value is to be updated and anotherexpression that specifies the new value of the node
While modifying an untyped XML instance the target expression should return a simply typed node In the case of a typedXML instance the target expression should evaluate to the same type or a subtype of the source expression
Syntax
replace value ofExpression1
withExpression2
Example Updating a skill
The following example shows how to update an existing skill value for a specified candidate using the replace value ofkeyword
Stored procedure to update a specified skill element for a candidate CREATE PROCEDURE [UpdateSkillInfo]
JobCandidateID [int]SkillOld [varchar](200)SkillNew [varchar](200)
ASBEGIN
SET NOCOUNT ON
UPDATE [CandidateInfoXMLDataType]SET Resumemodify(replace value of (JobCandidateSkillsSkill[=sqlvariable(SkillOld)]text())[1]with sqlvariable(SkillNew))WHERE JobCandidateID = JobCandidateID
END
Unlike the delete operation update and insert operations can only affect one node in one operation
XQuery Usage Scenarios
Scenario 1 Performance Appraisal System
The Human Resources department of an organization needs a performance appraisal system which can handle typicalappraisal-related activities for the company Typically appraisal records contain information that is mostly descriptive innature such as employee performance measured against the key objective set for the appraisal period defining keyobjectives for the next appraisal period identifying employee training needs and so on XML is best suited for handlingsuch information The appraisal information for an employee can be stored in a column of type XML which would allow theusers of the system to query and analyze the performance history of employees using XQuery Furthermore XML DML canbe used to modify the appraisal records
Let us assume that the training department of the organization is conducting a training session on ASPNET and would like
Copy Code
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
to invite all employees who requested training in ASPNET The following query selects all employees who opted for atraining session on ASPNET during their appraisal process
SELECT Appraisalquery(for $PA in PerformanceAppraisal
$Skill in $PATrainingNeedsTechnicalSkillwhere contains($Skill ASPNET)returnelement Employee
element EmpID data($PAEmployeeEmployeeID) element EmpName data($PAEmployeeEmployeeName) element EMail data($PAEmployeeEMailID) element Skill data($Skill)
) as ResultFROM [EmployeePerformanceAppraisal]WHERE Appraisalexist(PerformanceAppraisalTrainingNeedsTechnicalSkilltext()[contains(ASPNET)]) = 1
Scenario 2 Medical Records System
A hospital needs a system which can capture medical information related to patients This information includes patientdetails insurance information admission details diagnosis information treatment information and so on Thisinformation will be used for research or reference purposes XML is the format of choice for storing this information as thepatient medical data such as symptoms lab reports and treatment information contains descriptive information Patientdata can be stored in a column of type XML The hospital can use XQuery for analyzing this information
The following table and the XML instance are used to demonstrate the use of XQuery in a Patient Medical Recordsscenario
Table
CREATE TABLE [MedicalRecords]([PatientID] [int] IDENTITY(11) NOT NULL[PatientRecord] [xml] NOT NULL[ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
PRIMARY KEY CLUSTERED(
[PatientID] ASC) ON [PRIMARY]) ON [PRIMARY]GOCREATE PRIMARY XML INDEX idx_PatientRecord on [MedicalRecords] (PatientRecord)GOCREATE XML INDEX idx_PatientRecord_Path on [MedicalRecords] (PatientRecord) USING XML INDEXidx_PatientRecord FOR PATH
Sample XML Instance
ltPatientRecordgtltPatientDetailsgt
ltNamegtRobertltNamegtltGendergtMaleltGendergtltAgegt5ltAgegtltInsuranceInfogt
ltCompanygtBlue Cross Blue ShieldltCompanygtltIDgtD8456798ltIDgt
ltInsuranceInfogtltPatientDetailsgtltHospitalDetailsgt
ltNamegtKK HospitalltNamegtltDepartmentgtPediatricsltDepartmentgt
ltHospitalDetailsgtltAdmissionDetailsgt
ltRegistrationNogtD4321ltRegistrationNogtltDateAdmittedgt2004-05-02ltDateAdmittedgtltDateDischargedgt2004-05-08ltDateDischargedgt
Copy Code
Copy Code
Copy Code
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
ltAdmissionDetailsgtltProblemDetailsgtltSymptomsgt
ltSymptomgtAbdominal painltSymptomgtltSymptomgtDehydrationltSymptomgt
ltSymptomsgtltDiagnosisgtDiarrhealtDiagnosisgt
ltTreatmentInfogtltTherapygtOral Rehydration TherapyltTherapygtltPrescriptionDetailsgt
ltItemgtPepto-BismolltItemgtltItemgtElectrolyte SolutionsltItemgt
ltPrescriptionDetailsgtltTreatmentInfogt
ltProblemDetailsgtltPatientRecordgt
Let us assume that a doctor is interested in viewing the medical records of patients who were admitted with the symptomsof Fever and Abdominal Pain The following query retrieves records of patients who were admitted with the symptomsof Fever and Abdominal Pain
SELECT PatientID PatientRecordquery(element PatientName data(PatientRecordPatientDetailsName) element MedicalInfo PatientRecordProblemDetails
) as ResultFROM [MedicalRecords]WHERE PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Fever)]) = 1AND PatientRecordexist(PatientRecordProblemDetailsSymptomsSymptomtext()[contains(Abdominal Pain)]) = 1
Scenario 3 Asset Management System
The Information Technology department of an organization needs to develop an application which can manage assets suchas hardware and software This application should be capable of tracking information related to hardware assets includingAsset ID user details system information such as processor memory BIOS motherboard video card details softwareinstalled on the system purchase information and warranty information The application should also maintain informationrelated to the software assets of the organization such as software type number of licenses purchased etc Theapplication should be extensible to handle any new asset types that will be defined in the future This asset managementsystem will be used for generating reports such as hardware usage information software license usage information andhardware items due for maintenance In the current scenario there is a need for storing information confirming todifferent schemas in the same column of a table Untyped XML can be used to store information with varying schemasTyped XML with a schema collection can also be used to store such information The asset information stored as an XMLdata type can be queried using XQuery
Let us assume that the Information Technology department is interested in selecting a list of computer systems whereboth Microsoft Windows XP and Microsoft Office 2000 are installed The following query selects records of hardware assetswhere both Windows XP and Office 2000 are installed
SELECT AssetID AssetDetailsquery(ltAssetgt
element UserName data(AssetInfoUserInfoName) element ComputerName data(AssetInfoSystemInfoComputerName) element OS data(AssetInfoSystemInfoOS)
ltAssetgt
) as ResultFROM [Assets]WHERE Category = HardwareAND AssetDetailsexist(AssetInfoSystemInfoOStext()[contains(Windows XP)]) = 1AND AssetDetailsexist(AssetInfoSoftwaresInstalledSoftwaretext()[contains(Office2000)]) = 1
Conclusion
This paper serves as the starting point for readers who are interested in learning the basics of XQuery in the context ofSQL Server 2005 Different features of the XQuery language that are implemented in SQL Server 2005 along with non-supported features are discussed in the paper Examples illustrating the use of different features of XQuery language are
Copy Code
Copy Code
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]
also presented The XQuery usage scenarios in this paper will help the user to identify scenarios where using XQuery isappropriate
For more information
l XML Best Practices for Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345115(printer)aspx ]
l XML Support in Microsoft SQL Server 2005 [ httptechnetmicrosoftcomen-uslibraryms345117(printer)aspx ]
l Performance Optimizations for the XML Data Type [ httptechnetmicrosoftcomen-uslibraryms345118(printer)aspx ]