2779 Module 3 Using XML
-FOR XML clause can be used in select queries
-returns xml
-OPEN XML will transform XML into rows and columns
-returns rows and columns
-XML Datatype
For XML
Raw mode queries
Auto mode
Explicit mode
Path mode (easier to read)
Nested XML
FOR XML Claus
*Mark says XML is not meant for human consumption its meant to be consumed by applications.
RAW Mode Queries
-It’s a normal query but you throw FOR XML RAW on the end.
select top 1 * from HumanResources.Department
for
xml raw
--returns
<row DepartmentID="1"
Name="Engineering" GroupName="Research
and Development" ModifiedDate="1998-06-01T00:00:00"
/>
-Returns either elements or attributes
select top 1 * from HumanResources.Department
for
xml raw, elements
--returns
<row>
<DepartmentID>1</DepartmentID>
<Name>Engineering</Name>
<GroupName>Research
and Development</GroupName>
<ModifiedDate>1998-06-01T00:00:00</ModifiedDate>
</row>
-Can contain root element and row element name.
-If you use root you have to specify the root you are going to use.
select top
1 * from HumanResources.Department
for xml raw('Department'),root('Department') --replaces “row”
with “Product”
--returns
<Department>
<Department DepartmentID="1"
Name="Engineering" GroupName="Research
and Development" ModifiedDate="1998-06-01T00:00:00"
/>
</Department>
select top
1 * from HumanResources.Department
for xml raw('GroupName'),root('GroupName')
--returns
<GroupName>
<GroupName DepartmentID="1" Name="Engineering" GroupName="Research and Development" ModifiedDate="1998-06-01T00:00:00" />
</GroupName>
AUTO Mode Queries
-XML representation of data
-in a select statement that has a join, the results display the joined table as nested elements.
-Data is nested based on join precedence
-Can use options like ELEMENTS and ROOT
-Can NOT use group by (query a view instead to get around this if needed)
My Example:
select HD.Name,
HDH.EmployeeID from HumanResources.Department
HD
join HumanResources.EmployeeDepartmentHistory HDH
on (HD.Departmentid=HDH.DepartmentId)
where HD.Name in ('Engineering','Research
and Development')
order by HD.Name
for xml auto
--returns
<HD
Name="Engineering">
<HDH EmployeeID="3"
/>
<HDH EmployeeID="4"
/>
<HDH EmployeeID="9"
/>
<HDH EmployeeID="11"
/>
<HDH EmployeeID="12"
/>
<HDH EmployeeID="267"
/>
<HDH EmployeeID="270"
/>
</HD>
<HD
Name="Research and Development">
<HDH EmployeeID="79"
/>
<HDH EmployeeID="114"
/>
<HDH EmployeeID="158"
/>
<HDH EmployeeID="217"
/>
</HD>
My Example2:
select HDwheee.Name, HDHlalalala.EmployeeID
from HumanResources.Department HDwheee
join HumanResources.EmployeeDepartmentHistory HDHlalalala
on (HDwheee.Departmentid=HDHlalalala.DepartmentId)
where HDwheee.Name in ('Engineering','Research
and Development')
order by HDwheee.Name
for xml
auto
<HDwheee Name="Engineering">
<HDHlalalala EmployeeID="3" />
<HDHlalalala EmployeeID="4" />
<HDHlalalala EmployeeID="9" />
<HDHlalalala EmployeeID="11" />
<HDHlalalala EmployeeID="12" />
<HDHlalalala EmployeeID="267" />
<HDHlalalala EmployeeID="270" />
</HDwheee>
<HDwheee Name="Research and Development">
<HDHlalalala EmployeeID="79" />
<HDHlalalala EmployeeID="114" />
<HDHlalalala EmployeeID="158" />
<HDHlalalala EmployeeID="217" />
</HDwheee>
Retrieving Nested XML with (XML AUTO)
-AUTO mode returns either attributes or elements.
--ATTRIBUTES
SELECT Cust.CustomerID, CustomerTYpe,SalesOrderID,Status
FROM Sales.Customer Cust
Join Sales.SalesOrderHeader [Order]
ON Cust.CustomerID = [Order].CustomerID
ORDER
BY Cust.CustomerID
FOR XML AUTO
--returns:
<Cust CustomerID="1" CustomerTYpe="S">
<Order SalesOrderID="43860"
Status="5" />
<Order SalesOrderID="44501"
Status="5" />
<Order SalesOrderID="45283"
Status="5" />
<Order SalesOrderID="46042"
Status="5" />
</Cust>
<Cust CustomerID="2" CustomerTYpe="S">
<Order SalesOrderID="46976"
Status="5" />
<Order SalesOrderID="47997"
Status="5" />
<Order SalesOrderID="49054"
Status="5" />
<Order SalesOrderID="50216"
Status="5" />
<Order SalesOrderID="51728"
Status="5" />
<Order SalesOrderID="57044"
Status="5" />
<Order SalesOrderID="63198"
Status="5" />
<Order SalesOrderID="69488"
Status="5" />
</Cust>
--ELEMENTS:
SELECT Cust.CustomerID, CustomerTYpe,SalesOrderID,Status
FROM Sales.Customer Cust
Join Sales.SalesOrderHeader [Order]
ON Cust.CustomerID = [Order].CustomerID
ORDER
BY Cust.CustomerID
FOR XML AUTO,Elements
--returns
<Cust>
<CustomerID>1</CustomerID>
<CustomerTYpe>S</CustomerTYpe>
<Order>
<SalesOrderID>43860</SalesOrderID>
<Status>5</Status>
</Order>
<Order>
<SalesOrderID>44501</SalesOrderID>
<Status>5</Status>
</Order>
<Order>
<SalesOrderID>45283</SalesOrderID>
<Status>5</Status>
</Order>
<Order>
<SalesOrderID>46042</SalesOrderID>
<Status>5</Status>
</Order>
</Cust>
-use inner FOR XML with TYPE(returns XML datatype) clause to return xml data type
-- Nested XML with TYPE
SELECT
NAME CategoryName,
( SELECT
Name SubCategoryName
FROM Production.ProductSubCategory
SubCategory
WHERE SubCategory.ProductCategoryID
=
Category.ProductCategoryID
FOR XML AUTO, TYPE, ELEMENTS)
FROM Production.ProductCategory
Category
FOR
XML AUTO
--returns
<Category
CategoryName="Bikes">
<SubCategory>
<SubCategoryName>Mountain
Bikes</SubCategoryName>
</SubCategory>
<SubCategory>
<SubCategoryName>Road
Bikes</SubCategoryName>
</SubCategory>
<SubCategory>
<SubCategoryName>Touring
Bikes</SubCategoryName>
</SubCategory>
</Category>…snip
-You can combine EXPLICIT mode with UNION ALL
(insert example here I tried to make my own and it didn’t work)
Here is the slide---

Mark later demoed it and here is the syntax I still don’t really get how SQL Server knows how to convert this to XML
--
Nesting in EXPLICIT Mode
SELECT 1 AS TAG,
NULL AS Parent,
NULL AS [Review!2!Reviewer],
NULL AS [Review!2]
FROM Production.Product
WHERE
ProductID > 795
UNION
ALL
SELECT 2,
1,
p.ProductID,
NULL,
r.ReviewerName AS
[Review!2!Reviewer],
r.Comments AS [Review!2]
FROM Production.ProductReview r
JOIN Production.Product p
ON p.ProductID = r.ProductID
WHERE
p.ProductID > 795
ORDER
BY [Product!1!ProductID]
FOR
XML EXPLICIT
EXPLICIT Mode Queries (without nesting) (not normally used)
-3rd party application has specified EXACTLY how they want the data to be outputted.
Book Example:
SELECT
1 as Tag, NULL as Parent,
SalesOrderID
as [Invoice!1!InvoiceNo],
FROM Sales.SalesOrderHeader
FOR XML EXPLICIT
--results
<Invoice
InvoiceNo="43659">
<Date>2001-07-01T00:00:00</Date>
</Invoice>
<Invoice
InvoiceNo="43660">
<Date>2001-07-01T00:00:00</Date>
</Invoice>
<Invoice
InvoiceNo="43661">
<Date>2001-07-01T00:00:00</Date>
</Invoice>
<Invoice
InvoiceNo="43662">
<Date>2001-07-01T00:00:00</Date>
</Invoice>
…….snip
My Example (add TotalDue)
SELECT
1 as Tag, NULL as Parent,
SalesOrderID
as [Invoice!1!InvoiceNo],
FROM Sales.SalesOrderHeader
FOR XML EXPLICIT
<Invoice
InvoiceNo="43659">
<Date>2001-07-01T00:00:00</Date>
<Total>27231.5495</Total>
</Invoice>
<Invoice
InvoiceNo="43660">
<Date>2001-07-01T00:00:00</Date>
<Total>1716.1794</Total>
</Invoice>
<Invoice
InvoiceNo="43661">
<Date>2001-07-01T00:00:00</Date>
<Total>43561.4424</Total>
</Invoice>
<Invoice
InvoiceNo="43662">
<Date>2001-07-01T00:00:00</Date>
<Total>38331.9613</Total>
</Invoice>…snip
PATH Mode Queries
-a lot easier to construct than explicit mode
-uses XPath to specify the XML format
-Allows the creation of nested data
Book Example:
select EmployeeID '@EmpID',
FirstName 'EmpName/First',
LastName 'EmpName/Last'
from Person.Contact
inner join HumanResources.Employee
on Person.Contact.ContactID = Employee.ContactID
FOR XML PATH
--returns
<row EmpID="1">
<EmpName>
<First>Guy</First>
<Last>Gilbert</Last>
</EmpName>
</row>
<row
EmpID="2">
<EmpName>
<First>Kevin</First>
<Last>Brown</Last>
</EmpName>
</row>…snip
Mark Example:
SELECT ProductID AS
"@ProductID",
Size AS "Description/@Size",
FROM Production.Product
ORDER
BY Name
FOR XML PATH('Product')
--result
<Product ProductID="1">Adjustable
Race</Product>
<Product
ProductID="879">All-Purpose Bike
Stand</Product>
<Product
ProductID="712">AWC Logo
Cap<Description>Multi</Description></Product>
<Product
ProductID="3">BB Ball
Bearing</Product>
<Product
ProductID="2">Bearing
Ball</Product>
<Product
ProductID="877">
<Product
ProductID="316">Blade</Product>
<Product
ProductID="843">Cable
Lock</Product>
<Product
ProductID="952">Chain<Description>Silver</Description></Product>
<Product
ProductID="324">Chain
Stays</Product>
<Product
ProductID="322">Chainring<Description>Black</Description></Product>
<Product
ProductID="320">Chainring
Bolts<Description>Silver</Description></Product>
<Product
ProductID="321">Chainring
Nut<Description>Silver</Description></Product>
<Product
ProductID="866">Classic Vest,
L<Description Size="L">Blue</Description></Product>
<Product
ProductID="865">Classic Vest,
M<Description Size="M">Blue</Description></Product>
<Product
ProductID="864">Classic Vest,
S<Description Size="S">Blue</Description></Product>
Using OPEN XML
-taking XML and turning it into rows/columns
-aka shredding
-two sprocs involved
Steps:
General Syntax of process:

@doc variable holds the xml document
@hdoc (int) holds the value that uniquely identifies the internal tree structure
Call sproc and pass @hdoc as OUTPUT and in @doc
Sproc processes @doc and lets you know what @hdoc # is
When done
call remove sproc to delete the @hdoc tree from memory
Open XML Syntax (do this where the ”–process document” appears above)

DECLARE
@doc xml
SET
@doc = '<?xml version="1.0" ?>
<SalesInvoice
InvoiceID="1000" CustomerID="123"
OrderDate="2004-03-07">
<Items>
<Item ProductCode="12"
Quantity="2" UnitPrice="12.99"><ProductName>Bike</ProductName></Item>
<Item ProductCode="41"
Quantity="1" UnitPrice="17.45"><ProductName>Helmet</ProductName></Item>
<Item ProductCode="2"
Quantity="1" UnitPrice="2.99"><ProductName>Water Bottle</ProductName></Item>
</Items>
</SalesInvoice>'
DECLARE
@docHandle int
EXEC sp_xml_preparedocument @docHandle
OUTPUT, @doc
--
OPENXML using attributes only
SELECT
* FROM
OPENXML(@docHandle, '/SalesInvoice/Items/Item',
1)
WITH
( ProductCode int,
Quantity int,
UnitPrice float,
ProductName
nvarchar(20))
EXEC sp_xml_removedocument @docHandle
GO
--returns
ProductCode Quantity UnitPrice ProductName
-----------
----------- ---------------------- --------------------
12 2 12.99 NULL
41 1 17.45 NULL
2 1 2.99 NULL
XML Namespace
You can pass namespace info into openxml
XML DataType
-Native datatype
-Internal storage structure
-Tables, variables, or parameters
-Methods for querying and modifying XML
XQuery
-identifies the XML Nodes
/InvoiceList/Invoice[@InvoiceNo-2000]
-FLOWR statements (For Let Orderby Where Return)
For –iterates through nodes
Where – Applies filtering
Return - specifies xml to be returned
Query, Value, and Exist
Methods
-query returns untyped xml

-Value returns a scalar value

-Exist checks for the existence of a node

*if the invoice number of 1000 exists then this will return a 1 else 0
-Binding relational columns and variables (query method)

Modify Method
-insert add child nodes or siblings
Nodes Method
-shreds XML into relational data
-requires the APPLY operator with XML columns
Introducing XQuery
-is a query language that we use to identify nodes in an xml fragment
It uses FLOWR statements:

Expressions
Primary: ???
Sequence: [1]
Path: Relative Child::Address/child::Country
Absolute /Address/Country
Example:
declare @x xml
Set
@x = '<root>
<abc></abc>
<abc attrAbc="1"></abc>
<abc attrAbc="2"></abc>
</root>'
--Select
@x.query('/root/abc[atteAbc]')
Select @x.query('/root/abc[3]')