8、条件表达式(if(…) then … else …)
注意一点:else 表达式是必须的,即使不需要该表达式,也必须返回一个空序列(),如
declare @v varchar(10), @x xml
set @v = 'First'
set @x = ''
select @x.query('if (sql:variable("@v") = "First") then "Yes" else ()')
一个相对复杂的查询的示例:
declare @x xml
set @x = '<root>
<a type="node" childType="int"><b>1</b><b>2</b><b>3</b></a>
<a type="node" childType="text"><b>s1</b><b>s2</b><b>s3</b></a>
<a type="node" childType="double"><b>1.2</b><b>1.3</b></a>
</root>'
select @x.query('for $t in /root/a return
<result>
{ $t/@type } (: 选择属性,最终也是生成属性 :)
{ $t/@childType }
{
for $i in $t/*[position() <=2]
return $i
}
{
if (count($t/*) > 2) then
<more /> (: 直接在大括号中构建子元素 :)
else()
}
</result>')
9、限定表达式
( some | every ) <var> in <Exp1> satisfies <Exp2>
some:存在量词,Exp1 选定的序列有任意一项满足 Exp2,返回 true。
every:全称量词,Exp2 选定的序列必须全部满足 Exp2,才返回 true。
Exp2 返回的结果可以是节点序列、空序列或布尔值。
样例:
declare @x xml
set @x = '<root>
<a type="node" childType="int"><b>1</b><b>2</b><b>3</b></a>
<a type="node" childType="text"><b>s1</b><b>s2</b><b>s3</b></a>
<a type="node" childType="double"><b>1.2</b><b>1.3</b></a>
</root>'
select @x.query('if (every $i in //a satisfies count($i/*) = 3) then
"Yes" else "No"')
select @x.query('every $i in //a satisfies $i/b') – 判断 a 是否均有节点 b
select @x.value('some $i in //a satisfies count($i/*) = 3', 'varchar(10)')
10、SequenceType 表达式
在 XQuery 中,值始终是序列。值类型称为系列类型,序列类型可以用在 instance of XQuery 表达式中。当需要引用 XQuery 中的表达式类型时,应使用 XQuery 规范中的 SequenceType 语法。
(1) instance of 运算符
语法:Exp instance of SequenceTyep[基数]
若未指定基数,则默认为 1。基数可以为 ?、+、*,但 SQL Server 仅支持 “?”。”?” 表示 Exp 返回零项或一项,考虑下下面的例子:
Select @x.query('() instance of xs:integer?') – 有 ?,返回 true
Select @x.query('() instance of xs:integer') – 没有 ?,返回 false
l 对于非类型化节点的测试:
declare @x xml
set @x='<a attr1="x">1</a>'
select @x.query('/a[1] instance of element(a, xdt:untyped?)') -- true
select @x.query('data(/a[1]) instance of xdt:untypedAtomic') – true
l 通过 schema 自定义的类型,也可以使用 instance of 运算符:
create xml schema collection SC as '
<schema xmlns=http://www.w3.org/2001/XMLSchema
targetNamespace="SC" xmlns:sc="SC">
<element name="root" type="sc:custom" />
<complexType name="custom">
<sequence minOccurs="1" maxOccurs="unbounded">
<element name="a" type="integer" />
</sequence>
</complexType>
</schema>'
Go
declare @x xml(SC)
set @x = '<sc:root xmlns:sc="SC"><a>10</a><a>20</a></sc:root>'
select @x.query('declare namespace sc = "SC";
/sc:root[1] instance of element(sc:root, sc:custom?)')
注意命名空间的使用,set @x = '<sc:root xmlns:sc="SC"><a>10</a> <a>20</a></sc:root>' 这一句,也可以写成:
set @x = '<root xmlns="SC">
<a xmlns="">10</a><a xmlns="">20</a>
</root>'
如果写成
set @x = '<root xmlns="SC"><a>10</a><a>20</a></root>'
则会出现错误提示“预期的元素是 a,但指定的元素是 SC:a”。
l 如果在 schema 中定义了联合类型,对于使用联合类型的节点,SQL Server 在 XQuery 中可能无法判定该节点原子值所具有的真实类型。此时,可以判断联合类型中所包含的原子类型的顶级父类型。如:
CREATE XML SCHEMA COLLECTION MyTestSchema AS '
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://ns" xmlns:ns="http://ns">
<simpleType name="MyUnionType">
<union memberTypes="integer string"/>
</simpleType>
<element name="TestElement" type="ns:MyUnionType"/>
</schema>'
Go
DECLARE @var XML(MyTestSchema)
SET @var = '<TestElement xmlns="http://ns">123</TestElement>'
SELECT @var.query('declare namespace ns="http://ns";
data(/ns:TestElement[1]) instance of xs:decimal') – 返回 true
如果 data(/ns:TestElement[1]) instance of xs:decimal 换成
data(/ns:TestElement[1]) instance of xs:integer
则返回 false。因为 SQL Server 无法正确判定联合类型节点中节点原子值的真实原子类型,此时,应使用 xs:integer 的顶级父类型 xs:decimal 判定。
当然,仍然可以判定节点类型:
SELECT @var.query('declare namespace ns="http://ns";
/ns:TestElement[1] instance of element(ns:TestElement, ns:MyUnionType?)')
(2) cast as 运算符
语法:Exp cast as 原子类型?
在 SQL Server 中,“?”是必须的。另外,与日期时间相关的转换(xs:date、xs:time、xs:datetime)必须指定时区,时区由 Z 指定。