XML Querying with SQL Server – The Basics


SQL Server allows us to output the result set of a query as XML, it also allows us to shred the contents of an XML file into a table. 

An XML document is comprised of Tags and these start with < and end with /> so the following is an example of a tag. XML documents are ordered meaning that the position of the elements within the well-formed document matter.


<Customers>

More XML Here

</customers>

It’s worth remembering that XML documents are case-sensitive. XML documents have attributes an attribute is the following as shown in the below example.

<Customers>

<Customer custid=”1” CustomerName=”Max Smith”/>

</Customers>


In the example shown above an attribute is custid=”1” . When your XML document contains attributes it’s know as attribute-centric presentation. If your XML document does not contain attributes it’s know as element-centric presentation.

Producing XML using Queries

The following examples used the WideWorldImporters Database running on SQL server 2017. When creating XML documents, we use the FOR XML clause the first option is RAW.

 SELECT SH.[StockItemID]

             ,SI.StockItemName

     ,[QuantityOnHand]

     ,[BinLocation]

     ,[LastStocktakeQuantity]

     ,[LastCostPrice]

     ,[ReorderLevel]

     ,[TargetStockLevel]

     

     ,[LastEditedWhen]

 FROM [WideWorldImporters].[Warehouse].[StockItemHoldings] SH

 inner join Warehouse.StockItems as SI

 ON SI.StockItemID = SH.StockItemID

 for xml raw

This produced the following output

<row StockItemID="1" StockItemName="USB missile launcher (Green)" QuantityOnHand="175609" BinLocation="L-1" LastStocktakeQuantity="171341" LastCostPrice="9.50" ReorderLevel="20" TargetStockLevel="100" LastEditedWhen="2016-05-31T07:00:00" />

<row StockItemID="2" StockItemName="USB rocket launcher (Gray)" QuantityOnHand="165538" BinLocation="L-1" LastStocktakeQuantity="161435" LastCostPrice="9.50" ReorderLevel="20" TargetStockLevel="100" LastEditedWhen="2016-05-31T12:00:00" />

<row StockItemID="3" StockItemName="Office cube periscope (Black)" QuantityOnHand="253190" BinLocation="L-2" LastStocktakeQuantity="246900" LastCostPrice="11.25" ReorderLevel="10" TargetStockLevel="120" LastEditedWhen="2016-05-31T12:00:00" />

<row StockItemID="4" StockItemName="USB food flash drive - sushi roll" QuantityOnHand="208109" BinLocation="L-3" LastStocktakeQuantity="202964" LastCostPrice="12.00" ReorderLevel="5" TargetStockLevel="100" LastEditedWhen="2016-05-31T12:00:00" />



The above output shows that this is an XML fragment because it does not contain a root node. We can change this by including the ROOT(‘NAME’) option as shown.

SELECT SH.[StockItemID]

             ,SI.StockItemName

     ,[QuantityOnHand]

     ,[BinLocation]

     ,[LastStocktakeQuantity]

     ,[LastCostPrice]

     ,[ReorderLevel]

     ,[TargetStockLevel]

     

     ,[LastEditedWhen]

 FROM [WideWorldImporters].[Warehouse].[StockItemHoldings] SH

 inner join Warehouse.StockItems as SI

 ON SI.StockItemID = SH.StockItemID

 for xml raw, root('Stock')

This produced the following:

<Stock>

 <row StockItemID="1" StockItemName="USB missile launcher (Green)" QuantityOnHand="175609" BinLocation="L-1" LastStocktakeQuantity="171341" LastCostPrice="9.50" ReorderLevel="20" TargetStockLevel="100" LastEditedWhen="2016-05-31T07:00:00" />

 <row StockItemID="2" StockItemName="USB rocket launcher (Gray)" QuantityOnHand="165538" BinLocation="L-1" LastStocktakeQuantity="161435" LastCostPrice="9.50" ReorderLevel="20" TargetStockLevel="100" LastEditedWhen="2016-05-31T12:00:00" />

 <row StockItemID="3" StockItemName="Office cube periscope (Black)" QuantityOnHand="253190" BinLocation="L-2" LastStocktakeQuantity="246900" LastCostPrice="11.25" ReorderLevel="10" TargetStockLevel="120" LastEditedWhen="2016-05-31T12:00:00" />

 <row StockItemID="4" StockItemName="USB food flash drive - sushi roll" QuantityOnHand="208109" BinLocation="L-3" LastStocktakeQuantity="202964" LastCostPrice="12.00" ReorderLevel="5" TargetStockLevel="100" LastEditedWhen="2016-05-31T12:00:00" />

</stock>


To have the XML document returned as element-centric we add ELEMENTS to the options as shown below.

SELECT SH.[StockItemID]

             ,SI.StockItemName

     ,[QuantityOnHand]

     ,[BinLocation]

     ,[LastStocktakeQuantity]

     ,[LastCostPrice]

     ,[ReorderLevel]

     ,[TargetStockLevel]

     

     ,[LastEditedWhen]

 FROM [WideWorldImporters].[Warehouse].[StockItemHoldings] SH

 inner join Warehouse.StockItems as SI

 ON SI.StockItemID = SH.StockItemID

 for xml raw, elements,root('Stock')


This produces the following output

<Stock>

 <row>

   <StockItemID>1</StockItemID>

   <StockItemName>USB missile launcher (Green)</StockItemName>

   <QuantityOnHand>175609</QuantityOnHand>

   <BinLocation>L-1</BinLocation>

   <LastStocktakeQuantity>171341</LastStocktakeQuantity>

   <LastCostPrice>9.50</LastCostPrice>

   <ReorderLevel>20</ReorderLevel>

   <TargetStockLevel>100</TargetStockLevel>

   <LastEditedWhen>2016-05-31T07:00:00</LastEditedWhen>

 </row>

</stock>


XML Namespaces

We can add namespaces to our queries to help to distinguish between elements from different business areas, different companies and departments. The below example shows how to do this, also you can alias namespaces just as you do with tables.

 with xmlnamespaces('CustomerOrders' as co)

 select [co:customers].custid, [co:customers].contactname, [co:customers].contacttitle, [co:orders].shipcountry, [co:orders].orderdate

 from sales.customers as [co:customers]

 inner join sales.Orders as [co:orders]

 on [co:customers].custid= [co:orders].custid

 order by [co:customers].custid

 for xml auto, elements, root('Customers')

this produces the following output. (the below is just a snippet)


<Customers xmlns:co="CustomerOrders">

 <co:customers>

   <custid>1</custid>

   <contactname>Allen, Michael</contactname>

   <contacttitle>Sales Representative</contacttitle>

   <co:orders>

     <shipcountry>Germany</shipcountry>

     <orderdate>2015-08-25</orderdate>

   </co:orders>

   <co:orders>

     <shipcountry>Germany</shipcountry>

     <orderdate>2015-10-03</orderdate>

   </co:orders>

   <co:orders>

     <shipcountry>Germany</shipcountry>

     <orderdate>2015-10-13</orderdate>

   </co:orders>

   <co:orders>

     <shipcountry>Germany</shipcountry>

     <orderdate>2016-01-15</orderdate>

   </co:orders>

   <co:orders>

     <shipcountry>Germany</shipcountry>

     <orderdate>2016-03-16</orderdate>

   </co:orders>

   <co:orders>


It’s important to use the ORDER BY when producing XML from a SELECT statement. The reason being is that since we are formatting the XML by using the SELECT statement the ORDER BY gives us predictable results where as without the ORDER BY we would get unpredictable results.

You also need to make sure that the order of columns is correct in your SELECT list. This is due to the fact that the SELECT is formatting the XML document.

To view or add a comment, sign in

More articles by Joe Moore

  • Prevent Bulk Updates using Trigger in SQL Server

    Sometimes you need some protection in place on your important database tables to prevent an accidental bulk update of…

  • Understanding Window Functions in SQL Server

    Understanding Window Functions T-SQL supports window functions, a window function is a function that for each row…

  • Understanding Linux Filesystems

    Linux supports several types of filesystems to manage files and folders. Each filesystem implements the virtual…

  • Linux Network Commands and System Info

    In this article I would like to list the common Linux Network Commands, that can help in troubleshooting networking…

  • Working with Linux Users at the basic level

    Linux Security The core of the Linux security system is the user account. Each Individual who access a Linux system…

  • Wordpress wp-cron.php performance issue

    WordPress uses a file called wp-cron.php as a virtual cron job, or scheduled task in order to automate things like…

    1 Comment
  • Reset MySQL root Password

    Learn how to reset the MySQL root password, by reading my blog post. Read My Post

  • Configure Multiple Accounts cPanel and Sendgrid

    One of our managed dedicated server customers made contact with us, they wanted us to configure their cPanel based…

    1 Comment

Explore content categories