1. Trang chủ
  2. » Công Nghệ Thông Tin

Microsoft SQL Server 2008 R2 Unleashed- P192 potx

10 136 0

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 200,36 KB

Nội dung

ptg 1904 CHAPTER 47 Using XML in SQL Server 2008 for $outer in /outernode, $inner in $outer/innernode return <Outside letter=”{$outer/@name}”> <Inside number=”{$inner}”/> </Outside> ‘) go <Outside letter=”a”> <Inside number=”1” /> </Outside> <Outside letter=”a”> <Inside number=”2” /> </Outside> <Outside letter=”a”> <Inside number=”3” /> </Outside> <Outside letter=”b”> <Inside number=”4” /> </Outside> <Outside letter=”b”> <Inside number=”5” /> </Outside> <Outside letter=”b”> <Inside number=”6” /> </Outside> The let Clause New to SQL Server 2008, the let clause is the L in FLWOR. It performs the critical function of enabling variable value assignments in XQuery expressions. Here’s an example: WITH XMLNAMESPACES ( DEFAULT ‘http://schemas.microsoft.com/sqlserver/2004/07/adventure- works/StoreSurvey’ ) SELECT TOP 1 Demographics.query( ‘ for $N in /StoreSurvey let $Total := ($N/AnnualRevenue + $N/AnnualSales) order by $N/AnnualSales return <Statement AnnualRevenue=”{$N/AnnualRevenue}” ptg 1905 Using the xml Data Type 47 AnnualSales=”{$N/AnnualSales}” SalesPlusRevenue=”{$Total}”/> ‘) FROM Sales.Store WHERE Demographics.exist(‘(//AnnualRevenue[xs:integer(.)=300000])’) = 1 The where Clause Just like the WHERE clause in T-SQL, XQuery’s where clause restricts the nodes in the selected node list to those matching a certain expression. Here’s an example: SELECT TOP 1 Resume.query(‘ declare namespace ns=”http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/Resume”; for $ResumeNode in /ns:Resume where count($ResumeNode/ns:Employment) > 2 return $ResumeNode/ns:Employment/ns:Emp.JobTitle ‘) FROM HumanResources.JobCandidate go <ns:Emp.JobTitle xmlns:ns=”http://schemas.microsoft.com/sqlserver/2004/07/adventure- works/Resume”> Lead Machinist </ns:Emp.JobTitle> <ns:Emp.JobTitle xmlns:ns=”http://schemas.microsoft.com/sqlserver/2004/07/adventure- works/Resume”> Machinist </ns:Emp.JobTitle> <ns:Emp.JobTitle xmlns:ns=”http://schemas.microsoft.com/sqlserver/2004/07/adventure- works/Resume”> Assistant Machinist </ns:Emp.JobTitle> Here, you use the T-SQL-analogous count() aggregate function to restrict the result set to ns:Resume nodes having three or more ns:Employment children. The standard aggre- gate functions are available in XQuery expressions. They are max(), min(), avg(), sum(), and count(). The order by Clause Just like T-SQL’s ORDER BY, XQuery’s order by is used to reorder the selected nodes from the default document order to a new order, based on an expres- sion. The order may be set to descending or ascending (the default). ptg 1906 CHAPTER 47 Using XML in SQL Server 2008 The following example casts a node value to an instance of the xs:date type and orders the results from most to least recent date: SELECT Resume.query(‘ declare namespace ns=”http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/Resume”; <Achievements> { for $EducationNode in //ns:Education order by xs:date(string($EducationNode/ns:Edu.EndDate[1])) descending return <Degree> <DateAwarded> { string($EducationNode/ns:Edu.EndDate[1]) } </DateAwarded> <Name> { string($EducationNode/ns:Edu.Degree[1]) } </Name> </Degree> } </Achievements> ‘) FROM HumanResources.JobCandidate WHERE JobCandidateId = 2 go <Achievements> <Degree> <DateAwarded>1997-06-03Z</DateAwarded> <Name>Bachelor of Science</Name> </Degree> <Degree> <DateAwarded>1993-06-12Z</DateAwarded> <Name>Diploma</Name> </Degree> </Achievements> The expression xs:date(string($EducationNode/ns:Edu.EndDate[1])) requires some explanation. Working from the inside out: ns:Edu.EndDate is selected, using the child node of the node stored in the bound context variable $EducationNode. For the string() typecasting function to work, a singleton, or single node, must be specified; this is why the positional predicate [1] must be specified. Finally, the string is cast to xs:date. (Note that in the return statement, the string value of the same node is used.) This example illustrates not only the type-related aspects of FLWOR expressions, but also the capability to generate a root node without using FOR XML ROOT. All that is required is that a root node (in this case, Achievements), followed by curly braces, surround the entire FLWOR statement. ptg 1907 Using the xml Data Type 47 The return Clause Similar to T-SQL’s SELECT statement, the return clause executes once for every selected context node. This is the section where you specify the structure and content of the resulting XML. The key aspect of it is the use of node constructors. TIP When using attribute constructors in the return clause, you need to make sure your curly braces are directly adjacent to the attribute’s begin and end quotes, with no whitespace in between (for example, attribute=”{$Node}”), or SQL Server raises an error. The reason is that string literals (even blank spaces) cannot be mixed with attribute constructors. Put simply, constructors create the nodes and node values to be output. There are two types of constructors: . Computed constructors—These are placed inside curly-braced expressions and evaluated against the context node (for example, attribute=”{$N}”). . Direct constructors—These are constant node strings used in the FLWOR statement (for example, <Achievements>). Listing 47.16 illustrates a variety of constructors. LISTING 47.16 Using XQuery Constructors SELECT Resume.query(‘ declare namespace ns=”http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/Resume”; for $N in //ns:Education return <NodeConstructor attributeConstructor=”{string($N/ns:Edu.School[1])}”> { $N/ns:Edu.Major } <?PI processing-instruction constructor PI?> <! comment constructor > </NodeConstructor> ‘) FROM HumanResources.JobCandidate WHERE JobCandidateId = 1 go <NodeConstructor attributeConstructor=”Midwest State University”> <ns:Edu.Major xmlns:ns=”http://schemas.microsoft.com/sqlserver/2004/07/adventure- works/Resume”> Mechanical Engineering </ns:Edu.Major> <?PI processing-instruction constructor PI?> ptg 1908 CHAPTER 47 Using XML in SQL Server 2008 <! comment constructor > </NodeConstructor> Exactly the same XML result can be generated a third way: using the alternative node- type-name constructors (for example, element, attribute, text) in a comma-delimited list within curly braces. Here’s an example: SELECT Resume.query(‘ declare namespace ns=”http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/Resume”; for $N in //ns:Education return element NodeConstructor { attribute attributeConstructor { string($N/ns:Edu.School[1])}, text { string($N/ns:Edu.Major[1]) }, <?PI processing-instruction constructor PI?>, <! comment constructor > } ‘) FROM HumanResources.JobCandidate WHERE JobCandidateId = 1 TIP Because query() returns an instance of xml, the xml data type methods can be stacked on its result, allowing for powerful XQuery subqueries, such as query(‘’).query(‘’).exist(‘’). Testing XML by Using exist() A common task when working with XML is the need to check for the existence of a node or node value. The exist() method does just that, returning 1 if the node test returns nonempty, or 0 if empty. Listing 47.17 tests whether the annual revenue of a surveyed store exceeds $100,000. LISTING 47.17 Using exist() to Test for a Specific Node Value WITH XMLNAMESPACES ( DEFAULT ‘http://schemas.microsoft.com/sqlserver/2004/07/adventure- works/StoreSurvey’ ) SELECT Demographics.query( ptg 1909 Using the xml Data Type 47 ‘ for $N in /StoreSurvey order by $N/AnnualSales return if ($N/AnnualSales >= 3000000) then <Money Bank=”{$N/BankName}” AnnualRevenue=”{$N/AnnualRevenue}” AnnualSales=”{$N/AnnualSales}” Comments=”really big bucks”/> else <Money AnnualRevenue=”{$N/AnnualRevenue}” AnnualSales=”{$N/AnnualSales}” Comments=”big bucks”/> ‘) FROM Sales.Store WHERE Demographics.exist(‘ (//AnnualRevenue[xs:integer(.)>100000]) ‘) = 1 go <p1:Money xmlns:p1=”http://schemas.microsoft.com/sqlserver/2004/07/adventure- works/StoreSurvey” AnnualRevenue=”150000” AnnualSales=”1500000” Comments=”big bucks” /> <p1:Money xmlns:p1=”http://schemas.microsoft.com/sqlserver/2004/07/adventure- works/StoreSurvey” AnnualRevenue=”150000” AnnualSales=”1500000” Comments=”big bucks” /> <p1:Money xmlns:p1=”http://schemas.microsoft.com/sqlserver/2004/07/adventure- works/StoreSurvey” AnnualRevenue=”150000” AnnualSales=”1500000” Comments=”big bucks” /> <p1:Money xmlns:p1=”http://schemas.microsoft.com/sqlserver/2004/07/adventure- works/StoreSurvey” AnnualRevenue=”150000” AnnualSales=”1500000” Comments=”big bucks” /> <p1:Money xmlns:p1=”http://schemas.microsoft.com/sqlserver/2004/07/adventure- works/StoreSurvey” Bank=”International Bank” AnnualRevenue=”300000” AnnualSales=”3000000” Comments=”really big bucks” /> { } Listing 47.17 also illustrates the use of the XQuery if-then-else construct, which is used to conditionally generate the BankName attribute and change the value of the Comments attribute. In the WITH XMLNAMESPACES statement that precedes the query, you use the DEFAULT keyword to specify a default namespace for the selection. ptg 1910 CHAPTER 47 Using XML in SQL Server 2008 Converting a Node Value to a T-SQL Data Type by Using value() The value() function allows for a selected node value to be cast to a T-SQL–data typed value. It has two parameters: the first is a string-literal XPath expression that selects the desired node value. The second is a string-literal T-SQL data type name. The code in Listing 47.18 queries an Extensible Application Markup Language (XAML) document by using value() to select the Height attribute of Canvas nodes and cast them to decimal. Notice that the returned results are rows rather than XML. LISTING 47.18 Using value() to Retrieve and Convert a Node Value WITH XMLNAMESPACES ( ‘http://schemas.microsoft.com/winfx/2006/xaml’ as x, DEFAULT ‘http://schemas.microsoft.com/winfx/2006/xaml/presentation’ ) SELECT IllustrationID, Diagram.value(‘(//Canvas/@Height)[1]’, ‘decimal(16,4)’) HeightAsSQLDecimal FROM Production.Illustration go IllustrationID HeightAsSQLDecimal 3 147.7061 4 314.9819 5 105.7393 6 213.6152 7 177.5449 (5 row(s) affected) Accessing Relational Columns and T-SQL Variables in XQuery Expressions Besides value(), two other bridges between T-SQL and XQuery are the XQuery functions sql:column() and sql:variable(). sql:column(), as the name implies, allows for the selection of a relational column value in a FLWOR statement. In Listing 47.19, contact name data is pulled from Person.Person into an XQuery element constructor and then selected back out again as a node value. In addition, the value of the declared T-SQL variable TotalPurchaseYTD is compared against the value of the node of the same name in the XQuery where clause, using sql:variable(). LISTING 47.19 Using sql:column() and sql:variable() in XQuery DECLARE @TotalPurchaseYTD decimal(6,2) SET @TotalPurchaseYTD = 0 ptg 1911 Using the xml Data Type 47 SELECT Demographics.query(‘ declare default element namespace “http://schemas.microsoft.com/sqlserver/2004/07/adventure- works/IndividualSurvey”; for $IS in /IndividualSurvey where $IS/TotalPurchaseYTD[.= sql:variable(“@TotalPurchaseYTD”)] return element Contact { attribute ID { sql:column(“C.BusinessEntityID”) }, attribute YTDTotal { sql:variable(“@TotalPurchaseYTD”) }, element FullName { concat(sql:column(“FirstName”), “ “, sql:column(“LastName”)) } } ‘) FROM Sales.SalesPerson I JOIN Person.Person C ON C.BusinessEntityID = I.BusinessEntityID AND C.BusinessEntityID = 285 concat() is one of several string functions built into XQuery, in addition to contains(), substring(), and string-length(). Using the nodes() Method to Shred XML In the section “XML as Relational Data: Using OPENXML,” earlier in this chapter, you learned how to decompose XML directly into relational rows that could be mapped to values in existing tables or used any other T-SQL way. nodes() is kind of like OPENXML’s big brother: given an XML input document and an XQuery expression, it generates a table with an xml column against which subsequent XQuery queries can be run. nodes() can be applied to both xml variables and xml columns. Each row in the generated table contains a copy of the original input content. The context node for each row is based on the XQuery expression parameter. It is possible to shred the input in multiple ways by running multiple XQuery queries on the generated column in the same SELECT statement. For example, one query might return a relational value from each context node, using the value() method. Another could transform and return each content node to a different XML schema. Let’s examine a simple example that shows how this works. Listing 47.20 illustrates how an XML document is shredded into relational rows and columns by applying six different XQuery queries on each generated row, each of which creates a new relational column. ptg 1912 CHAPTER 47 Using XML in SQL Server 2008 LISTING 47.20 Shredding XML Six Ways, Using nodes() DECLARE @XmlVar xml SET @XmlVar = ‘ <alphnumerics> <item> <alph name=”A” val=”65”/> </item> <item> <alph name=”B” val=”66”/> </item> <item> <alph name=”C” val=”67”/> </item> <item> <num name=”1” val=”49”/> </item> <item> <num name=”2” val=”50”/> </item> <item> <num name=”3” val=”51”/> </item> </alphnumerics>’ SELECT XmlTable.XmlColumn.query(‘alph’) AS ANode, XmlTable.XmlColumn.value(‘alph[1]/@name’, ‘char(1)’) AS AName, XmlTable.XmlColumn.value(‘alph[1]/@val’, ‘int’) AS AVal, XmlTable.XmlColumn.query(‘num’) AS NNode, XmlTable.XmlColumn.value(‘num[1]/@name’, ‘int’) AS NName, XmlTable.XmlColumn.value(‘num[1]/@val’, ‘int’) AS NVal FROM @XmlVar.nodes(‘/alphnumerics/item’) AS XmlTable(XmlColumn) The syntax of nodes() is as follows: nodes(XQuery) AS GeneratedTableName(GeneratedXmlColumnName) Note that it is not possible to directly select the xml column generated by nodes without using one of the xml data type methods. Using the XML from the preceding example, the following code would raise an error: SELECT XmlTable.XmlColumn FROM @XmlVar.nodes(‘/alphnumerics/item’) AS XmlTable(XmlColumn) You can also use nodes() with CROSS APPLY or OUTER APPLY to execute nodes() once for every row returned in the outer table. In this way, you can combine relational data with multiple XQuery queries against a relational rowset. Listing 47.21 illustrates this technique. ptg 1913 Using the xml Data Type 47 LISTING 47.21 Using nodes() with CROSS APPLY WITH XMLNAMESPACES( ‘http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/Resume’ as ns ) SELECT JC.JobCandidateId, E.BusinessEntityID, ResumeTable.XmlColumn.value(‘ns:Emp.JobTitle[1]’, ‘nchar(50)’) JobTitle FROM HumanResources.JobCandidate JC CROSS APPLY JC.Resume.nodes(‘ /ns:Resume/ns:Employment[2] ‘) as ResumeTable(XmlColumn) JOIN HumanResources.Employee E ON E.BusinessEntityID = JC.BusinessEntityID go JobCandidateId EmployeeId JobTitle 4 274 Sales Associate 8 212 (2 row(s) affected.) Using modify() to Insert, Update, and Delete XML A frequent requirement when working with XML is the insertion, deletion, and modifi- cation of nodes and node values. These operations are known as XML Data Modification Language (XML DML) statements, and they are supported by the xml data type’s modify() method. When you are working with typed XML, modify() performs type and structural checks that allow operations to succeed only if they result in valid XML, so it’s important to know your schema well. When document order is important, it’s also crucial to know the exact location and posi- tion of the nodes or values to be changed. In the case of untyped or loosely constrained typed XML, it may not matter all that much where a new node is placed. XQuery provides a few functions and operators related to node order. position() returns the numeric position of a node (starting at 1). last() returns the numeric position of the last node in a selected node list. They are both performed against a context node. In addition, you can use the node order comparison operators << and >> to compare the relative positions of two selected nodes. The Boolean is operator is also provided to test whether two selected nodes are actually the same node. modify() allows for three main operations in its XQuery expression parameter: insert, replace value of, and delete. Let’s look at delete first. . HumanResources.JobCandidate go <ns:Emp.JobTitle xmlns:ns=”http://schemas .microsoft. com/sqlserver/2004/07/adventure- works/Resume”> Lead Machinist </ns:Emp.JobTitle> <ns:Emp.JobTitle xmlns:ns=”http://schemas .microsoft. com/sqlserver/2004/07/adventure- works/Resume”> Machinist </ns:Emp.JobTitle> <ns:Emp.JobTitle xmlns:ns=”http://schemas .microsoft. com/sqlserver/2004/07/adventure- works/Resume”> Assistant. xmlns:p1=”http://schemas .microsoft. com/sqlserver/2004/07/adventure- works/StoreSurvey” AnnualRevenue=”150000” AnnualSales=”1500000” Comments=”big bucks” /> <p1:Money xmlns:p1=”http://schemas .microsoft. com/sqlserver/2004/07/adventure- works/StoreSurvey”. xmlns:p1=”http://schemas .microsoft. com/sqlserver/2004/07/adventure- works/StoreSurvey” AnnualRevenue=”150000” AnnualSales=”1500000” Comments=”big bucks” /> <p1:Money xmlns:p1=”http://schemas .microsoft. com/sqlserver/2004/07/adventure- works/StoreSurvey”

Ngày đăng: 05/07/2014, 02:20

TỪ KHÓA LIÊN QUAN