4、算术表达式
(1) 算术运算符的参数必须为数字类型或 untypedAtomic。
(2) 不支持 idiv 运算符(idiv:整数除法,它返回一个整数值,忽略小数部分),可以通过以下方式模拟实现该运算符:
Select @x.query('xs:integer(2 div 3)')
5、比较表达式
(1) 常规比较运算符(=、!=、<、>、<=、>=)
常规比较运行符可用于:
l 两个序列的比较
l 序列与原子值的比较
l 两个原子值的比较
常规比较运算符只要其中任一项为真,则结果就为真,如
Select @x.query('(1, 2, 3) = (2, 5)') – 返回:true
Declare @y xml
Set @y = '<root><a>6</a><a>8</a></root>'
Select @y.query('//a < 7') – 返回:true
Select @y.query('//a > 7') – 返回:true
使用 = 运算符比较一个序列和一个原子值时,相当于测试该序列是否包含指定的原子值,如
Select @x.query('(1, 3, 4, 7) = 4')
在比较中,如果其中一个操作数是非类型化的,另一个是类型化的,则将非类型化的操作数转换为类型化操作数的类型。如果两个操作数都是非类型化的,则均转换为 xs:string。
(2) 值比较运算符(eq、ne(不等)、lt、gt、le(小于等于)、ge(大于等于))
值比较运算符只用于单一原子值,其操作数不能为序列(若空序列直接返回 false,单项序列会隐式调用 data() 函数获取类型化值,多项序列则会导致错误)。如:
Declare @x xml
Set @x = '<root><a>6</a><a>8</a></root>'
select @x.query('//a lt 7') – 错误
select @x.query('//a[1] lt 7') – 错误
select @x.query('(//a)[1] lt 7') – 返回:true
(3) 节点比较运算符(is)
测试两个节点是否是同一个节点,仅用于单一节点比较。如(接上例):
select @x.query('(//a)[1] is /root[1]/a[1]') – 返回:true
(4) 节点顺序比较运算符(<<、>>)
比较两个节点的先后关系,仅用于单一节点比较。
A << B,若节点 A 出现在节点 B 前面,返回 true,否则 false。
A >> B,若节点 A 出现在节点 B 后面,返回 true,否则 false。
6、XML 构造
所谓 XML 构造,其实就是通过 XQuery 构建一个新的 XML 格式文档。在 SQL Server XQuery 中,支持直接(direct)和(computed)构造,但因为计算构造时不允许动态计算节点的名称,所以两者在 SQL Server 中没有任何区别。
(1) 在 XQuery 中,使用 {} 可以明确指示大括号中的内容是查询表达式,而非常量。如:
declare @x xml
set @x = '<root><a>3</a><a>6</a></root>'
select @x.query('<NewRoot>{//a}</NewRoot>')
当然,也可以在大括号中使用函数:
select @x.query('<NewRoot>{data(//a)}</NewRoot>')
在些注一下 data() 和 string() 的区别:data() 可以接受一下序列,而返回的也是一个序列(原子值系列),而 string() 只能接受单一或空的序列,如下面的语句将会报错:
select @x.query('<NewRoot>{string(//a)}</NewRoot>') – 错误的
通过语句:
select @x.query('<NewRoot>{count(data(//a))}</NewRoot>')
可以很明显的看出 data() 返回的是一个序列。
若要在文本中使用 {},应使用转义 {{ 和 }}。
(2) 在大括号中包括完整的语句及嵌套大括号:
declare @x xml
set @x='
<root>
<step>This is step 1</step>
<step>This is step 2</step>
<step>This is step 3</step>
</root>'
select @x.query('<result>{for $i in /root/step return <s>{data($i)}</s>}</result>')
也可连续使用多个大括号:
select @x.query('<result>{string((//step)[1])} {string((//step)[1])}</result>')
注意:两个大括号间的空格会被忽略。
(3) 属性构造
属性可以接受原子值及原子值序列,如:
select @x.query('<result step="{(1, 2, 3)}" />')
这与下面的语句是等同的:
select @x.query('<result step="{1, 2, 3}" />')
都返回
<result step="1 2 3" />
在属性构造中传入节点时,会隐式调用 data(),如:
select @x.query('<result step="{//step}" />')
也可使用复杂的语句,如:
select @x.query('<result step="{for $i in //step where contains($i, "step") return $i}" />')
但是属性构造中不允许使用混合运算式,即要么使用单个大括号,要么直接使用常量值,不允许将常量和大括号混合使用,也不可以使用几个连续的大括号,如:
select @x.query('<result step="Step: {for $i in //step return $i}" />')
select @x.query('<result step="{string((//step)[1])}{string((//step)[2])}" />')
上述两个语句都是错误的。
那如何解决类似于上述的需求呢?
l 为属性表达式构建一个原子值序列,如:
select @x.query('<result step="{"Step: ", data(//step)}" />')
注意这里的 data(//step) 必须显式使用 data() 函数,否则系统会认为这是一个混合序列,而导致错误。当然,也可以在两边加上小括号明确标示序列。
l 使用 concat() 函数连接字符串参数
select @x.query('<result step="{concat("Step: ", (//step)[1])}" />')
因为 concat 第二个参数是一个字符串,所以只能接受单个或空的序列。下面的例子也可明确的看到 data() 返回的是序列:
select @x.query('<result step="{concat("Step: ", (data(//step))[1])}" />')
(4) 添加命名空间
select @x.query('<root xmlns="a"><a>1</a></root>')
指定前缀:
select @x.query('<x:root xmlns:x="a"><a>1</a></x:root>')
为子元素指定相同的命名空间:
select @x.query('<x:root xmlns:x="a"><x:a>1</x:a></x:root>')
新构造的命名空间可以在查询中使用:
SELECT Instructions.query('
declare namespace AWMI="http://someURI";
<FirstLocation xmlns:AWMI= "http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions" LocationID="{ (/AWMI:root/AWMI:Location[1]/@LocationID)[1] }"
SetupHrs="{ (/AWMI:root/AWMI:Location[1]/@SetupHours)[1] }" >
{ /AWMI:root/AWMI:Location[1]/AWMI:step }
</FirstLocation>
') as Result
FROM Production.ProductModel
where ProductModelID=7
这里包含着一个命名空间优先级的问题,命名空间的优先级从低到高排列如下:外部声明的WITH XMLNAMESPACES(URI as xx) --> XQuery 表达式内部的 declare namespace xx=URI --> 属性构造中的 xmlns:xx=URI
声明默认命名空间可采用如下方式:
declare @x xml
set @x ='<x>5</x>'
select @x.query('declare default element namespace "a";
<a><b xmlns=""/></a>')
(5) 计算构造 XML(仅支持 element、attribute、text)
declare @x xml
set @x=''
select @x.query('element root{
element a {attribute type {"text"}, text {"test"} },
element a {}
}')
返回值为:
<root><a type="text">test</a><a /></root>
对于空元素,名称后的大括号是必须的。
因为不支持动态生成节点名称,所以与直接构造相比,计算构造 XML 在 SQL Server XQuery中并没有什么优势。