当前位置导航:炫浪网>>网络学院>>编程开发>>MsSQL教程

SQL Server 2000 XML之七种兵器的说明


  XML,已成为近来最热门的Web技术,它是SQL Server 2000中的重要部分。本文将综合七条SQL Server 2000中最重要的XML综合特性组成XML之七种兵器。
  兵器之一:FOR XML
  
  在SQL Server 2000中,标准的T-SQL SELECT语句包括FOR XML子句,它以XML文档形式返回一个查询结果。新的FOR XML子句有三种模式——RAW,AUTO,和EXPLICIT,每个都能对XML文档格式提供附加标准的控制。
  
  下面首先介绍“FOR XML”的使用方法。
  
  为了从SQL Server提取XML格式的数据,T-SQL中加入了一个FOR XML命令。在查询命令中使用FOR XML命令使得查询结果以XML格式出现。FOR XML命令有三种模式:RAW,AUTO和EXPLICIT。图1所显示的SQL命令访问SQL Server提供的Pubs示例数据库。有关Pubs数据库的更多信息,请参见MSDN说明。如果我们依次指定该SQL命令的模式为三种允许的模式之一,就可以得到各种模式所支持的不同XML输出。
  
  SELECT store.stor_id as Id, stor_name as Name,
  
  sale.ord_num as OrderNo,sale.qty as Qty
  
  FROM stores store inner join
  
  sales sale on store.stor_id = sale.stor_id
  
  ORDER BY stor_name
  
  FOR XML <模式>
  
  该查询命令所生成的结果包含所有销售记录及其对应的商店,结果以商店名称的字母升序排列。查询的最后加上了FOR XML命令以及具体的模式,比如FOR XML RAW。
  
  理想情况下,SQL命令所生成的XML文档应具有如下结构:
  <Stores>
  
  <Store Id=&single;&single; Name=&single;&single;>
  
  </Sale OrderNo=&single;&single; Qty=&single;&single;>
  
  </Store>
  
  </Stores>
  
  下面我们来看看具体的处理方法。
  
  RAW模式
  下面是指定RAW模式时结果XML文档的一个片断。
  
  
 

  查询结果集中每一个记录包含唯一的元素<row>。由于我们无法控制元素名字和文档结构,因此这种模式不是很有用。RAW模式所生成的文档结构与我们所希望的不符,而且它的用途也非常有限。
  
  AUTO模式
  下面是指定AUTO模式时结果文档的一个片断:
  
  
 

  可以看到,<Stroe>和<Sale>两个元素是父-子关系,形成了我们所希望的层次结构。这种节点关系由查询中表的声明次序决定,后声明的表成为前声明表的孩子。
  
  我们可以看出查询命令所指定的别名决定了XML文档中的名字。根据这一点,我们可以控制XML文档元素、属性的名字,使得这些名字符合我们所要求的命名惯例。
  
  可见AUTO模式能够创建出我们所需要的XML文档。不过它存在以下缺点:
  
  虽然可以得到层次结构,但这种层次结构是线性的,即每个父节点只能有一个子节点,反之亦然。
  
  通过别名指定元素名字不太方便,而且有时候会影响查询命令本身的可读性。
  
  无法在文档中同时生成元素和属性。要么全部是元素(通过ELEMENTS关键词指定),要么全部是属性(默认)。 EXPLICIT模式解决了上述不足。
  
  EXPLICIT模式
  
  EXPLICIT模式比较复杂,我们将用另外一种方法来表达所显示的查询。这种方法使得我们能够完全地控制查询所生成的XML文档。首先我们将介绍如何改用EXPLICIT模式编写图1所显示的查询,然后看看这种方法如何赋予我们远远超过AUTO模式的能力。
  
  --商店数据
  SELECT 1 as Tag,
  NULL as Parent,
  s.stor_id as [store!1!Id],
  s.stor_name as [store!1!Name],
  NULL as[sale!2!OrderNo],
  NULL as [sale!2!Qty]
  FROM stores s
  UNION ALL
  -- 销售数据
  SELECT 2, 1,
  s.stor_id,
  s.stor_name,
  sa.ord_num,
  sa.qty
  FROM stores s, sales sa
  WHERE s.stor_id = sa.stor_id
  ORDER BY [store!1!name]
  FOR XML EXPLICIT
  
  这个查询初看起来有点复杂,其实它只是把不同的数据集(即这里的Store和Sale)分解到了独立的SELECT语句里,然后再用UNION ALL操作符连结成一个查询。
  
  我们之所以要把查询写成上面的形式,是为了让查询结果不仅包含XML文档所描述的数据,而且还包含描述XML文档结构的元数据。上述查询所生成的表称为Universal表,sqlxml.dll生成XML文档时需要这种格式。Universal表对于编写代码的人来说是透明的,但了解这个表还是很有意义的,它将有助于代码的开发和调试。下面是Universal表的一个例子:
  
  Tag Parent store!1!id store!1!name sale!2!orderno sale!2!qty
  1 NULL 7066 Barnum&single;s NULL NULL
  2 1 7066 Barnum&single;s A297650 50
  2 1 7066 Barnum&single;s QA7442 375
  1 NULL 8042 Bookbeat NULL NULL
  2 1 8042 Bookbeat 423LL9 2215
  
  Universal表和EXPLICIT模式查询的元数据部分都以红色表示,黑色表示数据。比较查询和表就可以找出sqlxml.dll生成XML文档所需要的元素。我们来仔细地分析一下它们描述的是什么。
  
  Tag和Parent列是XML文档层次结构方面的信息,我们可以认为每个SELECT语句代表了一个XML节点,而Tag和Parent列让我们指定节点在文档层次结构中的位置。如果在第二个SELECT语句中指定Tag为2、指定Parent为1,就表示为这些数据加上了一个值为2的标签,而这些数据的父亲是那些标签为1的数据(即第一个SELECT语句)。这就使得我们能够构造出<Store>和<Sale>之间的父-子关系,而且正如你可能猜想到的,它使得我们可以生成任意合法的XML文档结构。注意第一个SELECT命令的parent列设置成了NULL,这表示<Store>元素处于最顶层的位置。
  
  以黑色表示的数据将成为节点的属性或元素,例如,Store_ID就通过列名提供了这方面的信息。列名字中的“!”是分隔符,总共可分成四项(四个参数),其中第四个参数是可选的。这些参数描述的是:
  
  第一个参数描述该列所属元素的名字,在这里是<Store>元素。
  
  第二个是标签编号,它指定了该列信息在XML树形结构中所处位置。
  
  第三个参数指定XML文档内的属性或元素名字。在这里名字指定为id。
  
  数据列默认被创建为参数2所指定节点的属性,即id将成为<Store>节点的属性。如果要指定id是<Store>的一个子元素,我们可以使用第四个可选的参数,这个参数的一个作用就是让我们把该项指定为元素,例如store!1!id!element。
  
  由于使用了UNION ALL操作符来连结SELECT语句,为了保证SQL查询的合法性,所有SELECT语句的选择结果必须具有相同数量的列。我们使用NULL关键词来补足SELECT语句,从而避免了重复数据。
  
  通过EXPLICIT模式查询所生成的XML文档和通过AUTO模式生成的完全相同,那么为什么要创建EXPLICIT模式查询呢?
  
  假设现在有人要求在XML文档中包含商店的打折信息。查看Pubs数据库,我们得知每个商店都可以有0到n范围内的折扣率。因此,一种合理的方法是在<Store>元素下面加上子元素<Discount>,这样我们就得到如下XML文档结构:
  
  <STORES>
  <STORE Id=&single;&single; Name=&single;&single;>
  <DISCOUNT Type=&single;&single; LowQty=&single;&single; HighQty=&single;&single;>
  <AMOUNT></AMOUNT>
  </DISCOUNT>
  <SALE OrdNo=&single;&single; Qty=&single;&single;>
  </SALE>
  </STORE>
  </STORES>
  
  这里的改动包括:
  
  要在<Sale>元素所在的层次增加一个XML元素<Discount>,即<Discount>是<Stroe>的子元素。
  
  Amount嵌套在<Discount>里面,但不应该是<Discount>元素的属性。
  
  在AUTO模式中是不可能实现这些改动的。
  
  下面是创建这个新XML文档的EXPLICIT模式查询:
  
  SELECT 1 as Tag, NULL as Parent,
  s.stor_id as [Store!1!id],
  s.stor_name as [Store!1!name],
  NULL as [Sale!2!orderno],
  NULL as [Sale!2!1ty],
  NULL as [Discount!3!type],
  NULL as [Discount!3!lowqty],
  NULL as [Discount!3!highqty],
  NULL as [Discount!3!amount!element]
  FROM stores s
  UNION ALL
  SELECT 2, 1,
  s.stor_id,
  s.stor_name,
  sa.ord_num,
  sa.qty,
  NULL,
  NULL,
  NULL,
  NULL
  FROM stores s, sales sa
  WHERE s.stor_id = sa.stor_id
  UNION ALL
  SELECT 3, 1,
  NULL,
  s.stor_name,
  NULL,
  NULL,
  d.discounttype,
  d.lowqty,
  d.highqty,
  d.discount
  FROM stores s, discounts d
  WHERE s.stor_id = d.stor_id
  ORDER BY [store!1!name]
  For XML EXPLICIT
  
  为了创建图2A所显示的EXPLICIT模式查询,我们对图2的查询进行了如下修改:
  
  增加了第三个子查询提取折扣数据,通过Tag列声明这些数据的标签值为3。
  
  通过指定Parent列为1将折扣数据设置成<Store>元素的子元素。
相关内容
赞助商链接