7、FLWOR 语句和迭代
FLWOR 依次表示 for、let、where、order by、return。
(1) 最简单的 FLWOR 语句类似于:
for 变量 in 输入序列 return 返回值
输入序列顾名思义是接受一个序列,序列可以直接编写也可以通过 XQuery表达式获取。如:
declare @x xml
set @x='<root><a>1</a><a>2</a><a>3</a></root>'
select @x.query('for $i in (1, 2, 3) return $i')
select @x.query('for $i in //a return $i')
select @x.query('for $i in //a return $i + 1')
注意上面最后两个语句的区别,前者返回一个节点序列,而后者返回原子值序列。其实后者相当于:
select @x.query('for $i in //a return data($i) + 1')
(2) for … in … return 允许嵌套
select @x.query('for $i in
for $a in (1,2,3) return $a + 1
return $i')
因为SQL Server 的输入序列不接收用户构造的 XML 序列,所以下面的方式将会引发错误:
select @x.query('for $i in
for $a in (1,2,3) return <a>{$a}</a>
return $i')
(3) where 子句
declare @x xml
set @x='<ROOT><a>111</a></ROOT>'
SELECT @x.query('
for $a in (xs:string( "test"), xs:double( "12" ), data(/ROOT/a ))
where $a instance of xs:string
return $a')
该语句返回 test,如果 where 语句写为
where $a instance of xdt:untypedAtomic
将返回 111,即 /Root/a 节点包含的文本。
其实 where 相当于 Xpath 中的谓词测试,如:
declare @x xml
set @x='<ROOT><a><b>1</b></a><a /></ROOT>'
SELECT @x.query('for $a in //a where $a/* return $a')
这个语句返回 <a><b>1</b></a>,因为对于第二个 a 节点来说,$a/* 即 //a[2]/* 是一个空序列,此时 where 子句返回 false,因此该节点被过滤掉。
(4) let 子句
SQL Server 2005 并不支持 let 子句,这是 SQL Server 2008 中新增的特性。样例:
declare @x xml
set @x='<ROOT><a><b>1</b></a><a /></ROOT>'
SELECT @x.query('
for $a in (3, 6, 9)
let $s := $a * $a
return <value>Square({$a}) = {$s}</value>
')
(5) 多个变量绑定
declare @x xml
set @x='<Manu ID="1" Name="SomeBike" >
<Location ID="L1" >
<Step>Manu step 1 at Loc 1</Step>
<Step>Manu step 2 at Loc 1</Step>
<Step>Manu step 3 at Loc 1</Step>
</Location>
<Location ID="L2" >
<Step>Manu step 1 at Loc 2</Step>
<Step>Manu step 2 at Loc 2</Step>
<Step>Manu step 3 at Loc 2</Step>
</Location>
</Manu>'
SELECT @x.query('
for $Loc in /Manu/Location,
$FirstStep in $Loc/Step[1]
return
<Loc Id="{$Loc/@ID}">{$FirstStep}</Loc>
')
第二个变量不是必须和第一个变量相关,如上面的 $FirstStep 也可以为 $FirstStep in //Step[1],当然,这样会导致不同的结果。
另外,多变量绑定似乎和 for … in 的嵌套是一回事,如
SELECT @x.query('
for $Loc in /Manu/Location
for $FirstStep in $Loc/Step[1]
return
<Loc Id="{$Loc/@ID}">{$FirstStep}</Loc>
')
返回的结果是一样的,但 MSDN 中未明确说明。
(6) order by 子句
没什么好说的,就是排序,与 SQL 语句类似,降序的写法为
order by XXX descending
排序关键字必须是单一或空的序列,系统会隐式调用 data() 方法计算出原子值。
排序中可使用函数,如:
order by count($Loc/Step)
可按属性排序:order by $Loc/@ID
可按某个子节点值排序:order by $Loc/Step[1]
可按元素名称排序:order by local-name($Loc)
可指定多个排序关键字,同 SQL。