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

Hướng dẫn học Microsoft SQL Server 2008 part 51 pot

10 237 0

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

THÔNG TIN TÀI LIỆU

Nội dung

Nielsen c18.tex V4 - 07/21/2009 1:01pm Page 462 Part III Beyond Relational <LineItems ItemNo="D001" Qty="1" /> </Order> </Orders> */ Though the root element is correctly added, the XML output is not in the required structure. In fact, the information given is incorrect, because it shows that all three line items belong to Order SO102. This behavior is caused by the fact that the XML generator consumes rows in the same order as they are returned by the SELECT query. To generate the results in the correct order, the SELECT query should contain an ORDER BY clause that controls the order of the rows in the result set. The following example shows a new version of the query that generates a column just for the purpose of sorting. It then uses the HIDE directive to instruct SQL Server that the column should not be included in the XML output: SELECT 1 AS Tag, NULL AS Parent, CustomerNumber AS ‘Order!1!CustNo’, OrderNumber AS ‘Order!1!OrderNo’, REPLACE(STR(OrderID,4) + STR(0,4),’ ‘,’0’) AS ‘Order!1!Sort!HIDE’, NULL AS ‘LineItems!2!ItemNo’, NULL AS ‘LineItems!2!Qty’ FROM OrderHeader o INNER JOIN Customers c ON o.CustomerID = c.CustomerID UNION ALL SELECT 2 AS Tag, 1 AS Parent, NULL, NULL, REPLACE(STR(OrderID,4) + STR(OrderDetailID,4),’ ‘,’0’), i.ItemNumber, o.Quantity FROM Items i INNER JOIN OrderDetails o ON i.ItemID = o.ItemID ORDER BY ‘Order!1!Sort!HIDE’ FOR XML EXPLICIT, ROOT(’Orders’) /* <Orders> <Order CustNo="J001" OrderNo="SO101"> <LineItems ItemNo="D001" Qty="1" /> <LineItems ItemNo="Z001" Qty="1" /> </Order> <Order CustNo="J001" OrderNo="SO102"> <LineItems ItemNo="D001" Qty="1" /> </Order> </Orders> */ 462 www.getcoolebook.com Nielsen c18.tex V4 - 07/21/2009 1:01pm Page 463 Manipulating XML Data 18 That query could produce the correct result because of the ORDER BY clause present in the query. The ORDER BY clause ensures that the first row is the order header information for SO101 and that the next two rows contain order detail information for the same order. Again, it ensures that the next row is order header information for SO102, followed by the order detail information of the same order. The query returns the following result set (column names abridged for space): Tag Parent CustNo OrderNo Sort!HIDE ItemNo Qty 1 NULL J001 SO10 00010000 NULL NULL 2 1 NULL NULL 00010001 D001 1 2 1 NULL NULL 00010002 Z001 1 1 NULL J001 SO10 00020000 NULL NULL 2 1 NULL NULL 00020003 D001 1 As clearly apparent from the e xample, the ORDER BY clause has arranged the rows in the c orrect order using the arbitrary sort column. This result set is c onsumed by the XML generator and the output XML is generated in the correct order. One of the most common problems that people face with FOR XML EXPLICIT is ordering. It will be helpful in such cases to run the query without the FOR XML clause and inspect the output to ensure that the rows are in the correct order. FOR XML EXPLICIT supports a few more interesting directives, such as XML, XMLTEXT,andCDATA. The XML directive behaves very similarly to the ELEMENT directive. The only difference is that ELEMENT entitizes XML tags and XML preserves the XML tags: SELECT 1 AS Tag, NULL AS Parent, ‘<Info about="XML"/>’ AS ‘MyData!1!!ELEMENT’ FOR XML EXPLICIT /* ELEMENT directive encodes XML tags <MyData>&lt;Info about="XML"/&gt;</MyData> */ SELECT 1 AS Tag, NULL AS Parent, ‘<Info about="XML"/>’ AS ‘MyData!1!!XML’ FOR XML EXPLICIT /* XML directive preserves XML tags <MyData> <Info about="XML" /> </MyData> */ The XMLTEXT directive wraps the column content in a single tag and integrates i t with the rest of the document: SELECT 1 AS Tag, NULL AS Parent, 463 www.getcoolebook.com Nielsen c18.tex V4 - 07/21/2009 1:01pm Page 464 Part III Beyond Relational ‘<Info about="XML"/>’ AS ‘MyData!1!!XMLTEXT’ FOR XML EXPLICIT /* <MyData about="XML"></MyData> */ The CDATA directive wraps the value within a CDATA block in the output XML document. EXPLICIT is the only directive that can generate a CDATA section: SELECT 1 AS Tag, NULL AS Parent, ‘<Info about="XML"/>’ AS ‘MyData!1!!CDATA’ FOR XML EXPLICIT /* <MyData><![CDATA[<Info about="XML"/>]]></MyData> */ The ID, IDREF,andIDREFS directives can be used to create intra-document links. Another helpful directive that FOR XML EXPLICIT supports is ELEMENTXSINIL. The behavior of this directive is very similar to the XSINIL directive supported by AUTO and RAW. It is explained in the section ‘‘XSINIL Directive’’ later in this chapter. FOR XML PATH FOR XML PATH was introduced in SQL Server 2005. It is a lightweight alternative to FOR XML EXPLICIT . FOR XML PATH is as powerful as FOR XML EXPLICIT and as simple as FOR XML AUTO and RAW. The previous section demonstrated the complexity of using a FOR XML EXPLICIT query. FOR XML PATH has a simple syntax and supports generating almost all XML document structures previously possible only with FOR XML EXPLICIT. Thetruepowerof FOR XML PATH can be experienced when the XML structure is complex and has a multi-level hierarchy. It may be interesting to compare the complexity of code needed to produce the same XML document using FOR XML EXPLICIT and FOR XML PATH. The following example shows a sample XML document that will be generated using FOR XML PATH and FOR XML EXPLICIT to see the extent of the simplicity that FOR XML PATH provides to the SQL programmer: <Orders> <Order OrderNumber="SO102"> <Customer CustomerNumber="J001" /> <LineItems> <Item ItemNo="D001" Qty="1" /> </LineItems> </Order> </Orders> 464 www.getcoolebook.com Nielsen c18.tex V4 - 07/21/2009 1:01pm Page 465 Manipulating XML Data 18 The preceding XML document contains information about a sales order. The following example shows the FOR XML EXPLICIT code needed to produce the preceding output: SELECT 1 AS Tag, NULL AS Parent, OrderNumber AS ‘Order!1!OrderNumber’, NULL AS ‘Customer!2!CustomerNumber’, NULL AS ‘LineItems!3!’, NULL AS ‘Item!4!ItemNo’, NULL AS ‘Item!4!Qty’ FROM OrderHeader oh WHERE OrderID = 2 UNION ALL SELECT 2 AS Tag, 1 AS Parent, NULL, c.CustomerNumber, NULL, NULL, NULL FROM OrderHeader oh INNER JOIN Customers c ON oh.CustomerID = c.CustomerID AND OrderID = 2 UNION ALL SELECT 3 AS Tag, 1 AS Parent, NULL, NULL, NULL, NULL, NULL UNION ALL SELECT 4 AS Tag, 3 AS Parent, NULL, NULL, NULL, i.ItemNumber, od.Quantity FROM OrderDetails od INNER JOIN Items i ON i.ItemID = od.ItemID AND od.OrderID = 2 FOR XML EXPLICIT,ROOT(’Orders’) /* <Orders> <Order OrderNumber="SO102"> <Customer CustomerNumber="J001" /> <LineItems> <Item ItemNo="D001" Qty="1" /> </LineItems> </Order> </Orders> */ 465 www.getcoolebook.com Nielsen c18.tex V4 - 07/21/2009 1:01pm Page 466 Part III Beyond Relational The following example shows the FOR XML PATH query needed to produce the same XML output: SELECT oh.OrderNumber AS ‘@OrderNumber’, c.CustomerNumber AS ‘Customer/@CustomerNumber’, i.ItemNumber AS ‘LineItems/Item/@ItemNo’, od.Quantity AS ‘LineItems/Item/@Qty’ FROM OrderHeader oh INNER JOIN Customers c ON oh.CustomerID = c.CustomerID AND OrderID = 2 INNER JOIN OrderDetails od ON od.OrderID = oh.OrderID INNER JOIN Items i ON i.ItemID = od.ItemID FOR XML PATH(’Order’),ROOT(’Orders’) /* <Orders> <Order OrderNumber="SO102"> <Customer CustomerNumber="J001" /> <LineItems> <Item ItemNo="D001" Qty="1" /> </LineItems> </Order> </Orders> */ The amount of simplicity and power that comes with FOR XML PATH is apparent from the preceding example. The true power comes f rom the fact that FOR XML PATH allows generating deep hierarchies based on the column name. The column name LineItems/Item/@Qty creates an Item element with a Qty attribute under LineItems. An a ttribute is created by prefixing the name with an @ sign: SELECT CustomerID AS ‘@CustomerID’, OrderNumber AS ‘OrderNumber’ FROM OrderHeader FOR XML PATH(’Order’), ROOT(’Orders’) /* <Orders> <Order CustomerID="1"> <OrderNumber>SO101</OrderNumber> </Order> <Order CustomerID="1"> <OrderNumber>SO102</OrderNumber> </Order> </Orders> */ FOR XML PATH supports a number of special characters to achieve different XML formatting require- ments. For example, a ‘‘mixed’’ type element (an element that has a text value as well as attributes) can be created by naming a column with an asterisk ( ‘‘*’’), as shown in the following example: SELECT CustomerID AS ‘@CustomerID’, 466 www.getcoolebook.com Nielsen c18.tex V4 - 07/21/2009 1:01pm Page 467 Manipulating XML Data 18 OrderNumber AS ‘*’ FROM OrderHeader FOR XML PATH(’Order’), ROOT(’Orders’) /* <Orders> <Order CustomerID="1">SO101</Order> <Order CustomerID="1">SO102</Order> </Orders> */ The same result can be obtained by using the special column name indicators data(), node(), or text(). The data() indicator can also be used to generate a space-separated list of values by making the PATH name empty: SELECT ItemNumber AS ‘data()’ FROM Items FOR XML PATH(’’), ROOT(’Items’) /* <Items>D001 Z001</Items> */ Using the text() indicator along with e mpty PATH name will generate a similar string, but without spaces between the values: SELECT ItemNumber AS ‘text()’ FROM Items FOR XML PATH(’’), ROOT(’Items’) /* <Items>D001Z001</Items> */ Finally, a comment can be generated using the special column name indicator comment() along with FOR XML PATH: SELECT ‘Order Number’ AS ‘comment()’, OrderNumber, ‘Customer ID’ AS ‘comment()’, CustomerID FROM OrderHeader WHERE OrderID = 1 FOR XML PATH(’’), ROOT(’Orders’) /* <Orders> <! Order Number > <OrderNumber>SO101</OrderNumber> <! Customer ID > 467 www.getcoolebook.com Nielsen c18.tex V4 - 07/21/2009 1:01pm Page 468 Part III Beyond Relational <CustomerID>1</CustomerID> </Orders> */ FOR XML PATH is both powerful and easy to use. It offers a great deal of control over the structure of the output document. Most operations previously possible only with complex FOR XML EXPLICIT queries are now possible with FOR XML PATH. TYPE directive A FOR XML query returns a result set with one row and one column containing an NVARCHAR(MAX) value. The TYPE directive can be used to request SQL Server to return an XML data type value, instead of NVARCHAR(MAX). FOR XML queries can take advantage of the TYPE directive in a number of ways. FOR XML AUTO and RAW are relatively simple to use, but they provide very little control over the struc- ture of the XML result. The TYPE directive can be used to write nested FOR XML queries with FOR XML AUTO and RAW, which offers greater control over the structure of the XML o utput. For example, the following XML output cannot be achieved with FOR XML AUTO or RAW without using anested FOR XML query: <SalesOrder OrderNumber="SO101"> <Customer CustomerNumber="J001" Name="Jacob Sebastian"/> <Items> <Item ItemNumber="D001" Quantity="1" Price="900.0000" /> <Item ItemNumber="Z001" Quantity="1" Price="200.0000" /> </Items> </SalesOrder> The following example shows a nested FOR XML AUTO query that generates the preceding XML output: SELECT SalesOrder.OrderNumber, SalesOrder.OrderDate, ( SELECT CustomerNumber, Name FROM Customers Customer FOR XML AUTO, TYPE ), ( SELECT ItemNumber, Quantity, Price FROM ( SELECT i.ItemNumber, o.Quantity, o.Price FROM Items i INNER JOIN OrderDetails o ON i.ItemID = o.ItemID WHERE OrderID = 1 ) Item FOR XML AUTO, ROOT(’Items’),TYPE ) 468 www.getcoolebook.com Nielsen c18.tex V4 - 07/21/2009 1:01pm Page 469 Manipulating XML Data 18 FROM OrderHeader SalesOrder WHERE OrderID = 1 FOR XML AUTO Because the TYPE directive generates an XML data type value, instead of NVARCHAR(MAX),theresult of a FOR XML query that uses the TYPE directive can be used as input for other XML operations. The following example demonstrates this: SELECT ( SELECT OrderID, CustomerID FROM OrderHeader FOR XML AUTO, TYPE ).value(’(OrderHeader/@OrderID)[1]’,’INT’) AS OrderID /* OrderID 1 */ The inner q uery in the preceding example returns an XML data type value and hence it is possible to invoke XML data type methods such as value() or query() on the FOR XML query result. XSINIL Directive Let us look at two examples: Example 1: <Employee> <FirstName>Jacob</FirstName> <Employee> Example 2: <Employee> <FirstName>Jacob</FirstName> <HireDate xsi:nil="true" /> <Employee> Example 3: <Employee> <FirstName>Jacob</FirstName> <HireDate >1900-01-01</HireDate> </Employee> By default, FOR XML does not include columns with NULL values in the XML output. Some applications might need to process missing values different from NULL values. Those applications might require that an XML element be present in the XML document, even if the value is NULL. FOR XML supports a 469 www.getcoolebook.com Nielsen c18.tex V4 - 07/21/2009 1:01pm Page 470 Part III Beyond Relational special directive, XSINIL, that helps to achieve this. XSINIL is applicable only to elements, and can be used only with the ELEMENTS directive. When XSINIL is specified, FOR XML generates an empty element for any column that has a NULL value: SELECT OrderNumber, CustomerID, NULL AS CustomerPhone FROM OrderHeader [Order] FOR XML AUTO, ELEMENTS XSINIL /* <Order xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <OrderNumber>SO101</OrderNumber> <CustomerID>1</CustomerID> <CustomerPhone xsi:nil="true" /> </Order> */ Note that an empty CustomerPhone element is created in the preceding example, along with a special attribute xsi:nil set to ˝ true˝. It signals the XML parser that the element has a NULL value. Generating XML Schema information FOR XML AUTO and RAW provide very little control over the structure of the XML document. The docu- ment is usually structured based on the tables, columns, and joins used in the SELECT query. Because the structure of the XML document is based on the order of the columns in the select list and the way joins are applied in the query, it is important to tell any applications that consume the XML result about the structure of the XML document. An XML document is usually described using a schema. SQL Server can generate an XML or XDR (XML Data Reduced) schema along with the query results of a FOR XML AUTO or RAW query. FOR XML EXPLICIT and PATH are usually used to generate XML documents as per a given structure or schema; hence, support for generating schema information is not available with these options. An XDR schema can be generated along with the output by specifying the XMLDATA directive as part of the FOR XML query: SELECT OrderNumber, CustomerID FROM OrderHeader [Order] FOR XML AUTO, XMLDATA Similarly, the XMLSCHEMA directive can be used to generate an XML schema describing the output XML document: SELECT OrderNumber, CustomerID FROM OrderHeader [Order] FOR XML AUTO, XMLSCHEMA 470 www.getcoolebook.com Nielsen c18.tex V4 - 07/21/2009 1:01pm Page 471 Manipulating XML Data 18 A client application that processes the XML output will read the inline schema information before processing the XML document and understand the structure of the XML document. An optional target namespace can be specified along with the XMLSCHEMA directive. If a target namespace is specified, the XML output will be generated with a target namespace declaration: SELECT OrderNumber, CustomerID FROM OrderHeader [Order] FOR XML AUTO, XMLSCHEMA(’urn:some-namespace’) Generating XML namespaces XML uses namespaces to resolve ambiguity between elements or attributes referring to different contexts. All programming languages use some kind of operators to resolve ambiguity. T-SQL uses table aliases to resolve ambiguity — for example, ‘‘employee.name’’ is differentiated from ‘‘department.name.’’ .NET uses namespaces to avoid conflicts between objects inherited from different libraries. Similarly, XML documents use namespaces to avoid conflicts between elements or attributes with the same name. A FOR XML query can generate an XML document that contains one or more namespace declarations. The following code demonstrates an example that generates an XML document with a namespace declaration: ;WITH XMLNAMESPACES( ‘http://www.sqlserverbible.com/orders’ AS ord ) SELECT CustomerID AS ‘@CustomerID’, OrderNumber AS ‘data()’ FROM OrderHeader FOR XML PATH(’Order’),ROOT(’Orders’) /* <Orders xmlns:ord="http://www.sqlserverbible.com/orders"> <Order CustomerID="1">SO101</Order> <Order CustomerID="1">SO102</Order> </Orders> */ A default namespace declaration can be added by using the DEFAULT clause along with the namespace declaration: ;WITH XMLNAMESPACES( DEFAULT ‘http://www.sqlserverbible.com/orders’ ) SELECT CustomerID AS ‘@CustomerID’, OrderNumber AS ‘data()’ FROM OrderHeader FOR XML PATH(’Order’),ROOT(’Orders’) /* 471 www.getcoolebook.com . generates a column just for the purpose of sorting. It then uses the HIDE directive to instruct SQL Server that the column should not be included in the XML output: SELECT 1 AS Tag, NULL AS Parent, CustomerNumber. the section ‘‘XSINIL Directive’’ later in this chapter. FOR XML PATH FOR XML PATH was introduced in SQL Server 2005. It is a lightweight alternative to FOR XML EXPLICIT . FOR XML PATH is as powerful. row and one column containing an NVARCHAR(MAX) value. The TYPE directive can be used to request SQL Server to return an XML data type value, instead of NVARCHAR(MAX). FOR XML queries can take advantage

Ngày đăng: 04/07/2014, 09:20

TỪ KHÓA LIÊN QUAN