比较表达式 (XQuery)

XQuery 提供了下列类型的比较运算符:

  • 常规比较运算符

  • 值比较运算符

  • 节点比较运算符

  • 节点顺序比较运算符

常规比较运算符

常规比较运算符可用于比较原子值、序列或二者的任意组合。

下表中定义了常规运算符。

运算符

说明

=

等于

!=

不等于

<

小于

>

大于

<=

小于等于

>=

大于等于

使用常规比较运算符比较两个序列时,如果第二个序列中存在某个值与第一个序列中的某个值比较结果为 True,则整个结果为 True。否则为 False。例如,(1, 2, 3) = (3, 4) 为 True,因为值 3 同时出现在两个序列中。

declare @x xml
set @x=''
select @x.query('(1,2,3) = (3,4)')  

若要进行比较,值应是可比较的类型。具体来说,对这些值是进行静态检查的。对于数值比较,可能会出现数值类型提升。例如,如果对十进制值 10 与双精度值 1e1 进行比较,则将十进制值更改为双精度值。注意,由于双精度比较不可能很精确,因此得到的结果并不精确。

如果其中一个值是非类型化的,则将其转换为另一个值的类型。在下面的示例中,将值 7 视为一个整数。在进行比较之前,将非类型化值 /a[1] 转换为一个整数。该整数比较返回 True。

declare @x xml
set @x='<a>6</a>'
select @x.query('/a[1] < 7')

相反,如果将非类型化值与字符串或其他非类型化值进行比较,则将其转换为 xs:string。在下面的查询中,对字符串 6 与字符串“17”进行比较。因为是字符串比较,所以下面的查询返回 False。

declare @x xml
set @x='<a>6</a>'
select @x.query('/a[1] < "17"')

下面的查询从 AdventureWorks 示例数据库中提供的产品目录中返回某个产品型号的小尺寸图片。该查询将 PD:ProductDescription/PD:Picture/PD:Size 返回的一组原子值与一个单一序列“small”进行比较。如果比较结果为 True,则返回 <Picture> 元素。

WITH XMLNAMESPACES ('https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription' AS PD)
SELECT CatalogDescription.query('       
    for $P in /PD:ProductDescription/PD:Picture[PD:Size = "small"]       
    return $P') as Result       
FROM   Production.ProductModel       
WHERE  ProductModelID=19       

下面的查询将 <number> 元素中的一组电话号码与字符串文字“112-111-1111”进行比较。该查询对 AdditionalContactInfo 列中的一组电话号码元素进行比较,以确定文档中是否存在某个特定客户的特定电话号码。

WITH XMLNAMESPACES (
  'https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes' AS act,
  'https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInfo' AS aci)

SELECT AdditionalContactInfo.value('       
   /aci:AdditionalContactInfo//act:telephoneNumber/act:number = "112-111-1111"', 'nvarchar(10)') as Result       
FROM Person.Contact       
WHERE ContactID=1       

该查询返回 True。这表示文档中存在相应号码。下面的查询只对上面的查询稍微做了修改。在此查询中,将从文档中检索的电话号码值与包含两个电话号码值的组进行比较。如果比较结果为 True,则返回 <number> 元素。

WITH XMLNAMESPACES (
  'https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes' AS act,
  'https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInfo' AS aci)

SELECT AdditionalContactInfo.query('       
  if (/aci:AdditionalContactInfo//act:telephoneNumber/act:number = ("222-222-2222","112-111-1111"))       
  then        
     /aci:AdditionalContactInfo//act:telephoneNumber/act:number       
  else       
    ()') as Result       
FROM Person.Contact       
WHERE ContactID=1
       

结果如下:

<act:number 
  xmlns:act="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes">
    111-111-1111
</act:number>
<act:number 
  xmlns:act="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes">
    112-111-1111
</act:number> 

值比较运算符

值比较运算符用于比较原子值。注意,在查询中可以使用常规比较运算符来代替值比较运算符。

下表中定义了值比较运算符。

运算符

说明

eq

等于

ne

不等于

lt

小于

gt

大于

le

小于等于

ge

大于等于

如果根据所选的运算符两个值的比较结果相同,则表达式将返回 True。否则将返回 False。如果其中任何一个值是空序列,则表达式的结果为 False。

这些运算符只适用于单一原子值。也就是说,不能将一个序列指定为其中一个操作数。

例如,下面的查询将检索图片大小为“small”的产品型号的 <Picture> 元素。

SELECT CatalogDescription.query('       
              declare namespace PD="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";       
              for $P in /PD:ProductDescription/PD:Picture[PD:Size eq "small"]       
              return       
                    $P       
             ') as Result       
FROM Production.ProductModel       
WHERE ProductModelID=19       

注意上述查询的以下方面:

  • declare namespace 定义在随后的查询中使用的命名空间前缀。

  • <Size> 元素值与指定的原子值“small”进行比较。

  • 注意,由于值运算符只适用于原子值,因此隐式使用 data() 函数检索节点值。也就是说,data($P/PD:Size) eq "small" 生成相同的结果。

结果如下:

<PD:Picture 
  xmlns:PD="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription">
  <PD:Angle>front</PD:Angle>
  <PD:Size>small</PD:Size>
  <PD:ProductPhotoID>31</PD:ProductPhotoID>
</PD:Picture>

注意,用于值比较的类型提升规则与用于常规比较的类型提升规则相同。另外,在值比较过程中,SQL Server 对非类型化值使用的转换规则与它在常规比较过程中使用的转换规则相同。而 XQuery 规范中的规则是,在值比较过程中总是将非类型化值转换为 xs:string。

节点比较运算符

节点比较运算符 is 只适用于节点类型。它返回的结果表明作为操作数传入的两个节点是否表示源文档中的同一节点。如果两个操作数是同一节点,则此运算符返回 True。否则返回 False。

下面的查询检查在某个特定产品型号的生产过程中生产车间 10 是否排在第一位。

WITH XMLNAMESPACES ('https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions' AS AWMI)

SELECT ProductModelID, Instructions.query('       
    if (  (//AWMI:root/AWMI:Location[@LocationID=10])[1]       
          is        
          (//AWMI:root/AWMI:Location[1])[1] )        
    then       
          <Result>equal</Result>       
    else       
          <Result>Not-equal</Result>       
         ') as Result       
FROM Production.ProductModel       
WHERE ProductModelID=7         

结果如下:

ProductModelID       Result        
-------------- --------------------------
7              <Result>equal</Result>    

节点顺序比较运算符

节点顺序比较运算符根据节点在文档中的位置来比较节点对。

下面是根据文档顺序所做的比较:

  • <<:按照文档顺序先执行操作数 1,再执行操作数 2

  • >>:按照文档顺序先执行操作数 2,再执行操作数 1

下面的查询针对某个特定产品,如果在文档顺序中,产品目录说明的 <Warranty> 元素出现在 <Maintenance> 元素之前,则返回 True。

WITH XMLNAMESPACES (
  'https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription' AS PD,
  'https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelWarrAndMain' AS WM)

SELECT CatalogDescription.value('
     (/PD:ProductDescription/PD:Features/WM:Warranty)[1] << 
           (/PD:ProductDescription/PD:Features/WM:Maintenance)[1]', 'nvarchar(10)') as Result
FROM  Production.ProductModel
where ProductModelID=19

注意上述查询的以下方面:

  • 在该查询中使用了 xml 数据类型的 value() 方法。

  • 将查询的布尔值结果转换为 nvarchar(10) 并返回该结果。

  • 该查询返回 True。