xmltable

Description

Extracts data from an XML document and returns it as a SQL table.

Syntax

 xmltable_expression ::= xmltable
     ( row_pattern passing xml_argument
     columns column_definitions 
     options_parameter)
 row_pattern ::= character_string_literal
 xml_argument ::=  xml_expression
 column_definitions ::=
     column_definition [ { , column_definition } ]
       column_definition ::=
     ordinality_column | regular_column
 ordinality_column ::= column_name datatype for ordinality
 regular_column ::=
     column_name datatype [ default literal ] [null | not null]
 [ path column_pattern ]
 column_pattern ::= character_string_literal
 options_parameter ::=[,] option option_string
 options_string ::= basic_string_expression

Derived table syntax Returns a SQL table from within a SQL from clause.

 from_clause ::= from table_reference [, table_reference]...
 table_reference ::= table_view_name | ANSI_join |derived_table  table_view_name::=See the select command in Reference Manual 		                                Volume 2, "Commands".
 ANSI_join::=See the select command in Reference Manual 	                                 Volume 2, "Commands".
 derived_table ::=
      (subquery) as table_name [ (column_name [, column_name]...)       xmltable_expression as table_name

Examples

Example 1

xmltable as derived tables This example shows a simple xmltable() call, returning a derived table.

select * from xmltable('/doc/item'
	passing '<doc><item><id>1</id><name>Box</name></item>'
		+'<item><id>2</lid><name>Jar</name></item></doc>'
	columns id int path 'id',name varchar(20) path 'name') as items_table
id					name
-----           -----
1               Box
2               Jar

(2 rows affected)

Example 2

The syntax of derived tables requires you to specify a table name (items_table), even if you do not reference it. For example, this example is incorrect.

select * from xmltable ('/doc/item'
	passing '<doc><item><id>1</id><name>Box</name></item>'
		+'<item><id>2</id><name>Jar</name></item></doc>'
	columns id int path 'id', name varchar(20) path 'name')
-------------
Msg 102 Level 15, State 1:
Incorrect syntax near ')'

Example 3

Simple document reference examples In document references, the argument following passing is the input XML document. In this example the document is specified as a character string literal.

select * from xmltable ('/doc/item'
	passing '<doc><item><id>1</id><name>Box</name></item>'
		+'<item><id>2</id><name>Jar</name></item></doc>'
	columns id int path 'id', name varchar(20) path 'name') as items_table

id              name
-------         ------
1               Box
2               Jar

(2 rows affected)

Example 4

This example shows storing the document in a T-SQL variable, and referencing that variable in the xmltable() call.

declare @doc varchar(16384)
set @doc='<doc><item><id>1</id></name>Box</name></item>'
		+'<item><id>2</id><name>Jar</name></item></doc>'

select * from xmltable(/doc/item' passing @doc
	columns id int path 'id', name varchar(20) path 'name') as items_table

id            name
----          -----
1             Box
2             Jar

(2 rows affected)

Example 5

To store the document in a table and reference it with a scalar subquery:

select 100 as doc_id,	'<doc><item><id>1</id><name>Box</name></item><item><id>2</id>
	<name>Jar</name>			</item></doc>'as doc
into #sample_docs
select* from xmltable('/doc/item'
	passing(select doc from #sample_docs where doc_id=100)
	columns id int path 'id',name varchar(20) path 'name') as items_table

id            name
-------       -----
1             Box
2             Jar

(2 rows affected)

Example 6

Row patterns The first argument in the xmltable call, the row-pattern (’/doc/item’) is an XPath query expression whose result is a sequence of elements from the specified document. The xmltable call returns a table with one row for each element in the sequence.

Example 7

If the row pattern returns an empty sequence, the result is an empty table:

select * from xmltable ('//item_entry'
	passing '<doc><item><id>1</id><name>Box</name></item>'
		+'<item><id>2</id><name>Jar</name></item></doc>'
	columns id int path 'id', 
		name varchar(20) path 'name') as items_table

id               name
-------         ------


(0 rows affected)

Example 8

The row pattern expression cannot be an XPath function:

select * from xmltable ('/doc/item/tolower()'
	passing '<doc><item><id>1</id><name>Box</name></item>'
		+'<item><id>2</id><name>Jar</name></item></doc>'
	columns id int path 'id', 
		name varchar(20) path 'name') as items_table

id    name
---  ------
Msg 14825, Level 16, State 0:
Line1:
XPath function call must be at leaf level.

Example 9

Column patterns The arguments following the columns keyword is the list of column definitions. Each column definition specifies a column name and datatype, as in create table, and a path, called the column pattern. The column-pattern is an XPath query expression that applies to an element of the sequence returned by the row-pattern, to extract the data for a column of the result table.

Example 10

When the data for a column is contained in an XML attribute, specify the column pattern using "@" to reference an attribute. For example:

select * from xmltable ('/doc/item'
	passing '<doc><item id>"1"><name>Box</name></item>'
		+'<item id="2">/id><name><Jar</name></item></doc>'
	columns id int path '@id', name varchar(20)) as items_table

id              name
--------------------
1               Box
2               Jar

(2 rows affected)

Example 11

Default column patterns A column-pattern is commonly the same as the specified column_name, for example name. In this case, omitting the column-pattern results in defaulting to the column_name:

select * from xmltable ('/doc/item'
	passing '<doc><item><id>1</id><name>Box</name></item>'
		+'<item><id>2</id><name>Jar</name></item></doc>'
	columns id int, name varchar(20)) as items_table

id              name
--------------------
1               Box
2               Jar

(2 rows affected)

Example 12

If you want a column pattern to default to the column name, in a column whose value is in an XML attribute, use a quoted identifier. You must then quote such identifiers when you reference them in the results:

set quoted_identifier on
select "@id", name from xmltable ('/doc/item'
	passing '<doc><item id="1"><name>Box</name></item>'
		+'<item id="2"><name>Jar</name></item></doc>'
	columns "@id" int, name varchar(20)) as items_table

@id              name
--------------------
1               Box
2               Jar

(2 rows affected)

Example 13

You can also use quoted identifiers to specify column names as default column patterns, using column names that are more complex XPath expressions. For example:

set quoted_identifier on
select "@id", "name/short", "name/full" from xmltable ('/doc/item'
	passing '<doc><item id="1"><name><short>Box</short>
			 <full>Box, packing, moisture resistant, plain</full>
			 </name></item>'
	+'<item id="2"><name><short>Jar</short>
			 <full>Jar, lidded, heavy duty</full>
			 </name></item></doc>'
	columns "@id" int, "name/short" varchar(20), "name/full" varchar(50))
	as items_table

@id              name/short             name/full
--------------------
1               Box                     Box, packing, moisture resistant, plain
2               Jar                      Jar, lidded, heavy duty

(2 rows affected)

Example 14

Implicit text() This example demonstrates the function text(), which is generally implicit in the column pattern. text() removes XML element tags. For example, this XPath query returns the selected element with the XML markup:

1> declare @doc varchar(16384)
2> set @doc= ’<doc><item><id>1</id></name>Box</name></item>’
             +<’item><id>2</id><name>Jar</name></item></doc>’
3> select xmlextract(’/doc/item[2]/name’, @doc)
------------
<name>Jar</name>

Example 15

Adding text() to the XPath query removes the XML tags:

1> declare @doc varchar(16384)
2> set @doc= ’<doc><item><id>1</id></name>Box</name></item>’
             +<’item><id>2</id><name>Jar</name></item></doc>’

3> select xmlextract(’/doc/item[2]/name/text()’, @doc)
------------
Jar

Example 16

text() is implicit in most column patterns. This example does not specify text() in the column pattern for either the id or name column:

select * from xmltable ('/doc/item'
	passing '<doc><item><id>1</id><name>Box</name></item>'
		+'<item><id>2</id><name>Jar</name></item></doc>'
	columns id int path 'id', name varchar(20) path 'name') as items_table

id             name
---            -------
1              Box
2              Jar

(2 rows affected

)

Example 17

Datatype conversion You can derive column values in datatype conversions by applying an implicit SQL convert statement to the data extracted from the column pattern. For example:

select * from xmltable ('/emps/emp'
	passing '<emps>
<emp><id>1</id><salary>123.45</salary><hired>1/2/2003</hired></emp'
+'<emp><id>2</id><salary>234.56</salary><hired>2/3/2004</hired></emp>'
		+</emps>'
	columns id int path 'id', salary dec(5,2), hired date)
as items_table

id         salary        hired
-------    ---------     --------
1          123.45        Jan 2, 2003
2          234.56        Feb 3, 2004
(2 rows affected)

Example 18

The extracted XML data for the column must be convertible to the column datatype, or an exception is raised:

select * from xmltable ('/emps/emp'
	passing '<emps>
+<emp><id>1</id><salary>123.45</salary><hired>1/2/2003</hired></emp'
+'<emp><id>2</id><salary>234.56 C$</salary><hired>2/3/2004</hired></emp>'
+</emps>'
columns id int path 'id', salary dec(5,2), hired date)
as items_table
----------------------
Msg 14841, Level 16, State 3:
Line 1:
XMLTABLE:Failed to convert column pattern result to DECML for column 1.

Example 19

To handle XML data whose format is not suitable for a SQL convert function, extract the data to a string column (varchar, text, image, java.lang.String)

select * from xmltable ('/emps/emp'
	passing '<emps>
+<emp><id>1</id><salary>123.45</salary><hired>1/2/2003</hired></emp'
+'<emp><id>2</id><salary>234.56 </salary><hired>2/3/2004</hired></emp>'
+</emps>'
columns id int, salary varchar(20), hired date)
as items_table

id            salary         hired
---------------------------------
1             123.45        Jan 2, 2003
2             234.56       Feb 3, 2004
(2 rows affected)

Example 20

Ordinality columns The order of elements in XML documents can be significant.

Elements are sometimes ordered by the value of contained elements. In this example, the <item> elements are ordered by the value of the contained <id> elements.

<doc>
	<item><id>1<name>Box</name></item>'
	<item><id>2<name>Jar</name></item>'
</doc>

You can also order elements in an arbitrary but significant manner. In the following example, the order of the <item> elements is based on no values, but may reflect a priority ordering: first in, first out. Such an ordering can be significant for the application of the data.

<doc>
	<item><id>25<name>Box</name></item>'
	<item><id>15<name>Jar</name></item>'
</doc>

Example 21

You can use an ordinality_column in xmltable to record the ordering of elements in the input XML document:

declare @doc varchar(16384)
set @doc = '<doc><item><id>25<name>Box</name></item>'
	+'<item><id>15</id><name>Jar</name></item></doc'
select * from xmltable('/doc/item' passing @doc
	columns item_order int for ordinality,
		id int path 'id',
		name varchar(20) path 'name') as items_table
order by item_order

item_order         id            name
----------         ---           ----
1                  25            Box
2                  15            Jar
(2 rows affected)
-----------

Without the for ordinality clause and the item_order column, there is nothing in the id and name columns that indicates that the row of id 25 precedes the row of id 15. The for ordinality clause provides a way to make sure that the ordering of the output SQL rows is the same as the ordering of the elements in the input XML document.

The datatype of an ordinality column can be any fixed numeric datatype: int, tinyint, bigint, numeric, or decimal. numeric and decimal must have a scale of 0. An ordinality column cannot be real or float.

Example 22

Null values If a column pattern returns an empty result, the action taken depends on the default and {null | not null} clauses.

Example 23

This example omits the <name> element from the second <item>. The name column allows names by default.

select * from xmltable ('//item'
	passing '<doc><item><id>1</id><name>Box</name></item>'
	+'<item><id>2</id></item></doc>' 
columns id int path 'id', name varchar(20), path 'name')
as items_table
-------------------------
id            name
------------------
1             Box
2             NULL

(2 rows affected)

Example 24

This example omits the <name> element from the second <item>, and specifies not null for the name column:

select * from xmltable ('/doc/item'
	passing '<doc><item><id>1</id><name>Box</name></item>'
	+'<item><id>2</id></item></doc>' 
columns id int path 'id', name varchar(20) not null path 'name')
as items_table
-------------------------
Msg 14847, Level 16, State 1:
Line 1:
XMLTABLE column 0, does not allow null values.

Example 25

This example adds a default clause to the name column, and omits the <name> elements from the second <item>.

select * from xmltable ('/doc/item'
	passing '<doc><item><id>1</id><name>Box</name></item>'
	+'<item><id>2</id></item></doc>' 
columns id int path 'id' name varchar(20) default '***' path 'name')
as items_table

id            name
------------------
1             Box
2             ***
(2 rows affected)

Example 26

Context of xmltable calls These examples show SQL commands in which you can use an xmltable call in a derived table expression.

Example 27

select – You can use xmltable() in a simple select statement:

select * from xmltable ('/doc/item'
	passing '<doc><item><id>1</id><name>Box</name></item>'
	+'<item><id>2</id><name>Jar</name></item></doc>' 
columns id int path 'id' 
	name varchar(20) path 'name')as items_table

id            name
--            ----
1             Box
2             Jar
(2 rows affected)

Example 28

View definition – Specify select using xmltable in a view definition.This example stores a document in a table and references that stored document in a create view statement, using xmltable to extract data from the table:

select 100 as doc_id,
'<doc><item><id>1</id><name>Box</name></item>'
	+'<item><id>2</id><name>Jar</name></item></doc>' as doc
into sample_docs
create view items_table as
	select * from xmltable('/doc/item'
		passing (select doc from sample_docs where doc_id=100)
		columns id int path 'id' 
		name varchar(20) path 'name')as xml_extract

id            name
------------------
1             Box
2             Jar
(2 rows affected)

Example 29

Cursor declaration – Specify select using xmltable to declare a cursor:

declare cursor C for
select * from xmltable ('/doc/item'
	passing (select doc from sample_docs where id=100)
	columns id int path 'id' 
	name varchar(20) path 'name')as items_table
declare @idvar int
declare @namevar varchar(20)
open C
while @@sqlstatus=0
begin
fetch C into @idvar, @namevar
print 'ID "%1!" NAME"%2!"', @idvar, @namevar
end
-------------------------
ID "1" NAME "Box"
ID "2" NAME "Jar"
       
(2 rows affected)

In applications that require multiple actions for each generated row, such as executing update, insert, or delete from other tables, based on the data in each generated row, process an xmltable result with a cursor loop. Alternatively, you can store the xmltable result in a temporary table and process that table with a cursor loop.

Example 30

select into – Specify select using xmltable in select into:

select * into #extracted_table
from xmltable('/doc/item'
	passing (select doc from sample_docs where doc_id=100
	columns id int path 'id'
		name varchar(20) path 'name') as items_table

select * from #extracted_table

id            name
----          ------------
1             Box
2             Jar

Example 31

insert – Specify select using xmltable in an insert command:

create table #extracted_data (idcol int, namecol varchar(20))
insert into #extracted_data
select * into #extracted_table from xmltable('/doc/item'
	passing (select doc from sample_docs where doc_id=100
	columns id int path 'id', name varchar(20) path 'name')as items_table
select * from extracted_data

id             name
-----          ---------
1              Box
2              Jar
(2 rows affected)

Example 32

Scalar subquery – Specify select using xmltable in a scalar subquery. xmltable returns a SQL table, so the scalar subquery must perform either an aggregation or a selection to return a single row and column for the scalar subquery result.

declare @idvar int
set @idvar = 2
select @idvar,
(select name from xmltable ('/doc/item'
	passing(select doc from sample_docs where doc_id=100
	columns id int path 'id',name varchar(20) path 'name') as item_table
where items_table.id=@idvar)
----------------------------
2                     Jar
(1 rows affected)

Example 33

Joins – Join an xmltable result with other tables, using either comma-list joins or outer joins:

create table prices (id int, price decimal (5,2))
insert into prices values(1,123.45)
insert into prices values (2,234.56)
select prices.id,extracted_table.name, prices.price
from prices,(select * from xmltable('/doc/item'
	passing (select doc from sample_docs where doc_id=100
	columns id int path 'id', name varchar(20) path 'name')as a) as
             extracted_table
where prices.id=extracted_table.id

id       name        price
-----          ---------
1              Box   123.45
2              Jar   234.56
(2 rows affected)

Example 34

Processing tables of documents You can apply xmltable() to the XML document in each row of a table of XML documents. For example, the next example creates a table containing two columns:

create table high_priced_titles
(pub_id char(4), titles varchar (1000))
insert into high_priced_titles
select p.pub_id,
	(select title_id, price from pubs2..titles t,pubs2..publishers p
		where price> 15 and t.pub_id=p.pub_id
		for xml
		option 'tablename=expensive_titles, rowname=title')
			returns varchar(1000))as titles
from pubs2..publishers p
select * from high_priced_titles
--------------
pub_id    titles
------    -------------------------------------------------
0736             <expensive_titles>
	<title> <title_id>PS3333</title_id> <price>19.99</price></title>
	             </expensive_titles>

0877             <expensive_titles>
	<title> <title_id>MC2222</title_id> <price>19.99</price></title>
	<title> <title_id>PS1372</title_id> <price>21.59</price></title>
	<title> <title_id>TC3218</title_id> <price>20.95</price></title>
	             </expensive_titles>

01389             <expensive_titles>
	<title> <title_id>BU1032</title_id> <price>19.99</price></title>
	<title> <title_id>BU7832</title_id> <price>19.99</price></title>
	<title> <title_id>PC1035</title_id> <price>22.95</price></title>
	<title> <title_id>PC8888</title_id> <price>20.00</price></title>
	             </expensive_titles>
(3 rows affected)

Example 35

Use xmltable in a scalar subquery to process the XML document in each row, as a SQL table. For example, list the maximum title price for each publisher:

select pub_id
(select max(price)
 from xmltable('//title'passing hpt.titles
		columns title_id char(4), price money)
		as extracted_titles, high_priced_titles hpt) as max_price
 from high_priced_titles hpt
--------------
pubid         max_price
-----------------------
0736          19.99
0877          21.59
1389          22.95
	

This high_priced_titles table is essentially hierarchic: each row is an intermediate node, which contains, in its title column, a leaf node for each title element in the XML document. high_priced_titles has three rows.

You can flatten that hierarchy, producing a table with a row for each title element. To flatten the data in the titles column and produce a table, high_priced_titles_flattened, which has eight rows (one for each of the titles/title elements), use one of the following solutions.

Example 36

Solution 1 You can produce high_priced_titles_flattened by using a loop that processes high_priced_titles, and applies xmltable to the titles document in each row. In the example below, notice the from clause:

from(select @pub_id_var)as ppp,
	xmltable('//title' passing @titles_var
		columns title_id char(6),price money)as ttt

The variables @pub_id_var and @titles_var are the pub_id and titles columns from the current row of high_priced_titles. The from clause joins two derived tables:

To flatten the hierarchy, join these two derived tables, which appends the pub_id column to each row generated from the titles column:

create table high_priced_titles_flattened_1
(pub_id char(4), title_id(char(6), price money)

declare C cursor for select * from high_priced_titles
declare @pub_id_var char(4)
declare @titles_var char(1000)
open C

while @@sqlstatus =0
begin
fetch C into @pub_id_var, @titles_var

insert into high_priced_titles_flattened_1
select *
from (select @pub_id_var) as ppp,(col1),
	xmltable('//title' passing @titles_var
	columns title_id char (6), price money) as ttt
end
select * from high_priced_titles_flattened_1

pub_id    title_id          price
------    -------------------------------------------------
0736             PS3333               19.99
0877             MC2222               19.99
0877             PS1372               21.59
0877             TC3218               20.95
1389             BU1032               20.95
1389             BU7832               19.99
1389             PC1035               19.99
1389             PC8888               20.00

Example 37

Solution 2 You can also generate the high_priced_titles table using a special join.

This example joins two tables: high_priced_titles as hpt, and the table generated by xmltable. The passing argument of xmltable references the preceding hpt table. Normally, it is illegal to reference a table in a from clause, in a derived table expression within the same from clause. However, xmltable is allowed to reference other tables in the same from clause, as long as these tables precede the xmltable call in the same from clause.

select hpt.pub_id, extracted_titles.*
into high_priced_titles_flattened_3
from high_priced_titles as hpt,
		xmltable('//title'
		passing htp.titles,
		columns
			title_id char(6)
			price money)as extracted_titles
pub_id           title_id             price
---------        --------------       ---------
0736             PS3333               19.99
0877             MC2222               19.99
0877             PS1372               21.59
0877             TC3218               20.95
1389             BU1032               20.95
1389             BU7832               19.99
1389             PC1035               19.99
1389             PC8888               20.00

Usage

xmltable row and column patterns xmltable row and column patterns are allowed to be only simple paths. Simple paths in XPath consist only of forward traversals using '/' and element/attribute names.


Generating the rows of the result table

The result value of an xmltable expression is a T-SQL table RT, defined as follows:

See also

For a sample application using xmltable, see Appendix D, “Sample Application for xmltable(),”in XML Services.