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

Hướng dẫn học Microsoft SQL Server 2008 part 50 doc

10 348 0
Tài liệu đã được kiểm tra trùng lặp

Đ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 394,65 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

The following example demonstrates this: SELECT oh.OrderID, c.Name AS Customer, i.ItemDescription AS Item, x.value’@Quantity’,’INT’ AS Quantity, x.value’@Price’,’MONEY’ AS Price FROM Ord

Trang 1

INNER JOIN Customers c ON c.CustomerID = oh.CustomerID INNER JOIN Items i ON

i.ItemNumber = x.value(’@ItemNumber’,’CHAR(4)’) /*

- -

-1 Jacob Sebastian DELL XPS 1130 Laptop 1 900.00

1 Jacob Sebastian XBOX 360 Console 1 200.00

2 Jacob Sebastian DELL XPS 1130 Laptop 1 900.00

*/

The preceding example joins theOrderHeadertable with theOrderXMLtable and this join is between

a relational column and an XML node Again, another join is established between theItemstable and

theItemelements returned by thenodes()method

Another way to write this query is to embed the join operators as part of the XQuery expression itself

The following example demonstrates this:

SELECT oh.OrderID, c.Name AS Customer, i.ItemDescription AS Item, x.value(’@Quantity’,’INT’) AS Quantity, x.value(’@Price’,’MONEY’) AS Price FROM OrderHeader oh

INNER JOIN Customers c ON c.CustomerID = oh.CustomerID CROSS JOIN OrderXML

CROSS JOIN Items i CROSS APPLY ItemData.nodes(’

/Order[@OrderID=sql:column("oh.OrderID")]

/Item[@ItemNumber=sql:column("i.ItemNumber")]’) o(x) /*

- -

-1 Jacob Sebastian DELL XPS 1130 Laptop 1 900.00

1 Jacob Sebastian XBOX 360 Console 1 200.00

2 Jacob Sebastian DELL XPS 1130 Laptop 1 900.00

*/

The capability to join relational tables with XML nodes opens up a wide variety of possibilities to

per-form join operations between relational and XML data

Using variables and filters in XQuery expressions

SQL Server allows only string literals as XQuery expressions The following is illegal in SQL

Server 2008:

DECLARE @node VARCHAR(100) SELECT @node = ‘/Order/Item’)

Trang 2

/* columns here */

FROM OrderXML

CROSS APPLY ItemData.nodes(@node) o(x)

Although you might want to use such an expression, it won’t work; I see this in XML forums all the

time Don’t make the same mistake There are two common scenarios in which one might need to use

variables in XQuery expressions:

■ To apply filters on the value of elements or attributes; for example, to retrieve the nodes with

itemnumber= ‘‘Z001’’ or OrderID = ‘‘1’’

■ To retrieve the value of an element or attribute that is not known in advance, such as in cases

where the name of the element or attribute is passed as an argument

SQL Server allows using variables as part of an XQuery expression using thesql:variable()

func-tion The following example uses a variable to filter an item number from the XML node:

DECLARE @ItemNumber CHAR(4)

SELECT @ItemNumber = ‘D001’

SELECT

x.value(’@ItemNumber’,’CHAR(4)’) AS ItemNumber,

x.value(’@Quantity’,’INT’) AS Quantity,

x.value(’@Price’,’MONEY’) AS Price

FROM OrderXML

CROSS APPLY ItemData.nodes(’

/Order/Item[@ItemNumber=sql:variable("@ItemNumber")]’

) o(x)

/*

ItemNumber Quantity Price

- -

*/

Returning the values of elements or attributes not known in advance is a little trickier This can be

achieved by using the XQuery functionlocal-name()and by matching it with the value of the given

variable:

DECLARE @Att VARCHAR(50)

SELECT @Att = ‘ItemNumber’

SELECT

x.value(’@*[local-name()=sql:variable("@Att")][1]’,

‘VARCHAR(50)’) AS Value

FROM OrderXML

CROSS APPLY ItemData.nodes(’/Order/Item’) o(x)

/*

Trang 3

Value -D001

Z001 D001

*/

The preceding example retrieves the value of an attribute that is not known in advance The name of the

attribute is stored in a variable and the XQuery functionlocal-name()is used to match the name of

the attribute with the variable

Supporting variables as part of XQuery expressions greatly extends the power and flexibility of XQuery

programming possibilities within T-SQL

Accessing the parent node

Most of the time, a query retrieving information from an XML document needs to access information

from nodes at different levels in the XML tree The easiest way to achieve this may be by using the

par-ent node accessor, as shown in the following example:

SELECT x.value(’ /@OrderID’,’INT’) AS OrderID, x.value(’@ItemNumber’,’CHAR(4)’) AS ItemNumber, x.value(’@Quantity’,’INT’) AS Quantity,

x.value(’@Price’,’MONEY’) AS Price FROM OrderXML

CROSS APPLY ItemData.nodes(’/Order/Item’) o(x) /*

OrderID ItemNumber Quantity Price - - -

*/

The preceding example uses the parent node accessor ( ) to retrieve theOrderIDattribute While this

syntax is pretty simple and easy to use, it may not be good in terms of performance When the parent

node accessor is used, the XQuery processor needs to go backward to read the parent node information

while processing each row, which might slow down the query

The following example demonstrates a more optimized way of writing the preceding query usingCROSS

APPLY:

SELECT h.value(’@OrderID’,’INT’) AS OrderID, x.value(’@ItemNumber’,’CHAR(4)’) AS ItemNumber, x.value(’@Quantity’,’INT’) AS Quantity,

x.value(’@Price’,’MONEY’) AS Price

Trang 4

FROM OrderXML

CROSS APPLY ItemData.nodes(’/Order’) o(h)

CROSS APPLY h.nodes(’Item’) i(x)

/*

OrderID ItemNumber Quantity Price

- - -

*/

The firstCROSS APPLYoperator used in the preceding query retrieves an accessor to theOrder

element, and the secondCROSS APPLYreturns an accessor to eachItemelement This eliminates the

need to use the parent node accessor in the query to read information from theOrderelement

The parent node accessor may be fine with small tables and small XML documents, but it is not

recom-mended for large XML documents or tables A better way of accessing the parent node is by using the

CROSS APPLYapproach demonstrated in the preceding example

Generating XML Output Using FOR XML

FOR XMLis a row set aggregation function that returns a one-row, one-column result set containing an

NVARCHAR(MAX)value TheTYPEdirective can be used along withFOR XMLto produce XML data

type output instead of NVARCHAR(MAX)

FOR XMLcan be used with theAUTO,RAW,PATHandEXPLICITdirectives to achieve different levels of

control over the structure and format of the XML output

FOR XML AUTO

FOR XML AUTOis one of the easiest options available to generate XML output from results of aSELECT

query It returns XML output having nested XML elements Though it is easy to use and has a simple

syntax,FOR XML AUTOdoes not provide much control over the structure of the XML output

FOR XML AUTO, as the name suggests, ‘‘automatically’’ identifies the element names, hierarchies, and so

on, based on the table name, aliases, and joins used in the query The following example demonstrates a

basic use ofFOR XML AUTO:

SELECT OrderNumber, CustomerID

FROM OrderHeader

FOR XML AUTO

/*

<OrderHeader OrderNumber="SO101" CustomerID="1" />

<OrderHeader OrderNumber="SO102" CustomerID="1" />

*/

Trang 5

The element name is determined based on the name or alias of the table In the preceding example, an

element namedOrderHeaderis created because the name of the table isOrderHeader By adding an

alias to the table name, a different element name can be generated:

SELECT OrderNumber, CustomerID FROM OrderHeader o

FOR XML AUTO /*

<o OrderNumber="SO101" CustomerID="1" />

<o OrderNumber="SO102" CustomerID="1" />

*/

These examples produce XML fragments, and not valid XML documents A valid XML document can

have only one top-level element A root element can be added to the output of aFOR XML AUTOquery

by specifying theROOTdirective

TheROOTdirective takes an optional argument that specifies the name of the root element If this

argu-ment is not specified, the name of the top-level eleargu-ment will always be ‘‘root.’’ The following example

adds a top-level element namedSalesOrderto the XML output:

SELECT OrderNumber, CustomerID FROM OrderHeader

FOR XML AUTO, ROOT(’SalesOrder’) /*

<SalesOrder>

<OrderHeader OrderNumber="SO101" CustomerID="1" />

<OrderHeader OrderNumber="SO102" CustomerID="1" />

</SalesOrder>

*/

If the query has more than one table,FOR XML AUTOwill generate hierarchical XML output based on

the joins used in the query The example given here joins theOrdertable with theCustomerstable:

SELECT [Order].OrderNumber, [Order].OrderDate, Customer.CustomerNumber, Customer.Name FROM OrderHeader [Order]

INNER JOIN Customers Customer ON [Order].CustomerID = Customer.CustomerID FOR XML AUTO

/*

<Order OrderNumber="SO101" OrderDate="2009-01-23T00:00:00">

<Customer CustomerNumber="J001" Name="Jacob Sebastian" />

</Order>

*/

Trang 6

By default,FOR XML AUTOgenerates elements for each row, and values are generated as attributes This

behavior can be changed by specifying theELEMENTSdirective, which forces SQL Server to generate

values as attributes:

SELECT

[Order].OrderNumber, [Order].OrderDate,

Customer.CustomerNumber, Customer.Name

FROM OrderHeader [Order]

INNER JOIN Customers Customer ON [Order].CustomerID = Customer.CustomerID

FOR XML AUTO, ELEMENTS

/*

<Order>

<OrderNumber>SO101</OrderNumber>

<OrderDate>2009-01-23T00:00:00</OrderDate>

<Customer>

<CustomerNumber>J001</CustomerNumber>

<Name>Jacob Sebastian</Name>

</Customer>

</Order>

*/

AFOR XMLquery returns a result set with one row and one column containing anNVARCHAR(MAX)

value TheTYPEdirective can be used to request SQL Server to return an XML data type value, instead

ofNVARCHAR(MAX) TheTYPEdirective is explained in this chapter.FOR XML AUTOcan be used with

additional directives such asXSINIL,XMLDATA, andXMLSCHEMA, each of which is covered in detail

later in this chapter

FOR XML RAW

FOR XML RAWis very similar toFOR XML AUTO, differing from it in only a couple of ways One of the

basic differences betweenFOR XML AUTOandFOR XML RAWis that the former doesn’t allow altering

the name of the elements.FOR XML AUTOalways generates XML elements based on the name of the

table or alias

Conversely,FOR XML RAWgenerates elements named<row>by default, and allows customizing it An

optional element name can be specified with theRAWdirective and SQL Server will generate the

ele-ments with the specified name:

SELECT OrderNumber, CustomerID

FROM OrderHeader

FOR XML RAW(’Order’)

/*

<Order OrderNumber="SO101" CustomerID="1" />

<Order OrderNumber="SO102" CustomerID="1" />

*/

Trang 7

Another difference worth noticing is thatFOR XML AUTOgenerates a top-level element for each table used

in the query.FOR XML RAWgenerates only one top-level element for each row in the query result:

SELECT OrderNumber, CustomerNumber FROM OrderHeader o

INNER JOIN Customers c ON o.CustomerID = c.CustomerID FOR XML RAW(’Order’)

/*

<Order OrderNumber="SO101" CustomerNumber="J001" />

<Order OrderNumber="SO102" CustomerNumber="J001" />

*/

If the preceding query were executed withFOR XML AUTO, it would create a top-level element for the

order information and a child element for the customer information If theELEMENTSdirective is

speci-fied, SQL Server will create child elements for each column instead of attributes

Like theAUTOdirective,RAWalso supports an optionalROOTdirective that generates a root element

with the specified name If the root name is not specified, a top-level element named<root>will be

created:

SELECT OrderNumber, CustomerID FROM OrderHeader

FOR XML RAW(’Order’), ROOT(’Orders’) /*

<Orders>

<Order OrderNumber="SO101" CustomerID="1" />

<Order OrderNumber="SO102" CustomerID="1" />

</Orders>

*/

FOR XML RAWcan also be used with additional directives such asXSINIL,XMLDATA, andXMLSCHEMA,

covered in detail later in this chapter

FOR XML EXPLICIT

FOR XML EXPLICITis the most powerful clause available to generate XML output It can generate very

complex XML structures and offers a great deal of control over the output structure However, most

people find it too complicated to use

To useFOR XML EXPLICIT, each row should have two mandatory columns:TagandParent The

data should be such that a hierarchical relationship is established between the rows usingTagand

Parent Other columns should be named in a certain format that provides some additional metadata

information

The followingFOR XML EXPLICITquery generates an XML document with nested elements up to two

levels:

SELECT

1 AS Tag,

Trang 8

NULL AS Parent,

CustomerNumber AS ‘Customer!1!CustNo’,

NULL AS ‘LineItems!2!ItemNo’,

NULL AS ‘LineItems!2!Qty’

FROM OrderHeader o

INNER JOIN Customers c ON o.CustomerID = c.CustomerID

AND o.OrderID = 1

UNION ALL

SELECT

2 AS Tag,

1 AS Parent,

NULL,

i.ItemNumber,

o.Quantity

FROM Items i

INNER JOIN OrderDetails o ON i.ItemID = o.ItemID

AND o.OrderID = 1

FOR XML EXPLICIT

/*

<Customer CustNo="J001">

<LineItems ItemNo="D001" Qty="1" />

<LineItems ItemNo="Z001" Qty="1" />

</Customer>

*/

The results of the query without theFOR XML EXPLICITclause look like the following:

Tag Parent Customer!1!CustNo LineItems!2!ItemNo LineItems!2!Qty

- - - -

Essentially, to run aFOR XML EXPLICITquery, SQL Server needs data in a format similar to the one

given above.TagandParentare mandatory columns and they should maintain a valid parent-child

(hierarchical) relationship There should be at least one more additional column to run aFOR XML

EXPLICITquery successfully

The XML generator will read the results of the query and identify the hierarchy of the XML document

based on the hierarchical relationship specified byTagandParentcolumns The name of each

column specifies the name of its parent element, its position in the hierarchy, and the name of the

attribute.LineItems!2!Qtyindicates that the value should apply to an attribute namedQtyunder

theLineItemselement at hierarchy level two

Due to this complex structuring requirement of the query results, most people feel thatFOR XML

EXPLICITis overly complex However, on the positive side, it is very powerful and offers a number of

XML generation capabilities that no otherFOR XMLdirective offers

Trang 9

FOR XML EXPLICITallows creating XML documents to satisfy almost every complex customization

requirement The trick is to generate a result set with the required hierarchical relationship, and the

XML output will be generated accordingly

As shown in the preceding example, the names of the columns can be used to pass important metadata

information to SQL Server The previous example demonstrated a three-part column-naming convention

that specified the element name, tag number, and attribute name An optional fourth part can be used to

control a number of aspects of the XML generation process

By default,FOR XML EXPLICITgenerates values as attributes TheELEMENTSdirective can be used

to instruct SQL Server to generate a given column as an element TheELEMENTSdirective can be

spec-ified along with each column The following example demonstrates a slightly modspec-ified version of the

previous query that generates a customer number as an element:

SELECT

1 AS Tag, NULL AS Parent, CustomerNumber AS ‘Customer!1!CustNo!ELEMENT’, NULL AS ‘LineItems!2!ItemNo’,

NULL AS ‘LineItems!2!Qty’

FROM OrderHeader o INNER JOIN Customers c ON o.CustomerID = c.CustomerID AND o.OrderID = 1

UNION ALL SELECT

2 AS Tag,

1 AS Parent, NULL,

i.ItemNumber, o.Quantity FROM Items i INNER JOIN OrderDetails o ON i.ItemID = o.ItemID AND o.OrderID = 1

FOR XML EXPLICIT /*

<Customer>

<CustNo>J001</CustNo>

<LineItems ItemNo="D001" Qty="1" />

<LineItems ItemNo="Z001" Qty="1" />

</Customer>

*/

FOR XML EXPLICITprocesses rows in the same order as that returned by theSELECTquery If the

data in the output should appear in a specific order, then the order clause should be specified in

theSELECTquery Sometimes, it can happen that the order should be done on a column that is not

needed in the output XML

This might be a little tricky Because the final output is generated by a series of queries that uses

UNION ALL, the sort operation can be applied only on a column that already exists in the query results

However, often the column or expression to be used for the ordering might not be required in the XML

output

Trang 10

FOR XML EXPLICITsupports another directive,HIDE, that can be applied on columns that should

be excluded from the final output A column or expression that a query needs for sorting of the final

results can be marked asHIDEand will be excluded from the XML output

An example might best explain this The example demonstrated earlier in this section generated XML

output with information taken from only one order The next example tries to generate an XML

docu-ment with information from all the orders in the sample database It attempts to generate XML output as

follows:

<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>

Just as withRAWandAUTO,EXPLICITsupports theROOTdirective to generate a top-level element

The following example shows a slightly modified version of the previous query that has aROOTclause

and the filter for order ID removed:

SELECT

1 AS Tag,

NULL AS Parent,

CustomerNumber AS ‘Order!1!CustNo’,

OrderNumber AS ‘Order!1!OrderNo’,

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,

i.ItemNumber,

o.Quantity

FROM Items i

INNER JOIN OrderDetails o ON i.ItemID = o.ItemID

FOR XML EXPLICIT, ROOT(’Orders’)

/*

<Orders>

<Order CustNo="J001" OrderNo="SO101" />

<Order CustNo="J001" OrderNo="SO102">

<LineItems ItemNo="D001" Qty="1" />

<LineItems ItemNo="Z001" Qty="1" />

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