中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 数据库开发 > 数据库综合
使用Microsoft SQL Server 2000的XML查询
作者:未知 时间:2005-07-27 23:41 出处:CSDN 责编:chinaitpower
              摘要:使用Microsoft SQL Server 2000的XML查询

使用Microsoft SQL Server 2000XML查询

郑佐 2005-6-28

由于XML本身的诸多优点,XML技术已被广泛的使用,目前的好多软件技术同XML紧密相关,比如微软的.net 平台对xml提供了强大的支持,提供System.Xml以及其子命名空间下的类型来操作xmlAdo.net通过核心类型DataSet出色的把关系型数据库同xml进行了紧密集成。由于平常许多开发人员使用.net 来操作Sql server的到数据集后再转换成xml,所以往往忽略Transact-SQL查询生成XML数据的强大功能。对于一些项目使用XML查询直接通过SQL生成xml会来的更为简便,所以我通过在实际项目中的使用和查阅一些资料写成一个知识点,一是温故而知新,二是对于一些开发者刚好需要这方面的技术而还没有找到比较快捷的学习方式提供一条途径。

SQL SERVER 2000中查询生成XML的语法表达式比较简洁,整个语法如下:

SELECT <select_list>

FROM <table_source>

WHERE <search_condition>

FOR XML AUTO | RAW | EXPLICIT [,XMLDATA ] [,ELEMENTS] [,BINARY BASE64]

下面我将以Northwind数据库来演示上面的表达式中所包含的各项功能,下面的查询语句和返回结果都通过SQL SERVER 2000查询分析器来执行和得到。

 

一. 使用AUTO模式

该模式我认为在生成单表xml数据方面是用得最多的,能满足一般的需要。先来看他的简单查询。

1.简单查询

查询语句:

SELECT CategoryID,

CategoryName

FROM Categories

WHERE CategoryID < 3 FOR XML AUTO

返回结果:

<Categories CategoryID="1" CategoryName="Beverages"/>

<Categories CategoryID="2" CategoryName="Condiments"/>

也可以使用别名,

查询语句:

SELECT CategoryID AS ID,

CategoryName,

GetDate() as CurrDate

FROM Categories MyTable

WHERE CategoryID < 3 FOR XML AUTO

返回结果:

<MyTable ID="1" CategoryName="Beverages" CurrDate="2005-06-24T11:09:52.937"/>

<MyTable ID="2" CategoryName="Condiments" CurrDate="2005-06-24T11:09:52.937"/>

2.连接查询

以两个表为例,

查询语句:

SELECT Categories.CategoryID,

Categories.CategoryName,

ProductID,

ProductName

FROM Categories 

JOIN Products ON Categories.CategoryID = Products.CategoryID AND ProductID <5

WHERE Categories.CategoryID < 3 FOR XML AUTO

返回结果:

<Categories CategoryID="1" CategoryName="Beverages">

<Products ProductID="1" ProductName="Chai"/>

</Categories>

<Categories CategoryID="2" CategoryName="Condiments">

<Products ProductID="2" ProductName="Chang"/>

</Categories>

可以看到表连接查询可以生成分层次的Xml,不过需要注意的是SELECT子句中的父表的列要排在子表的列的前面,否则会出现你不想看到的结果,如:

查询语句:

SELECT ProductID,Categories.CategoryID,Categories.CategoryName,ProductName

FROM Categories 

JOIN Products ON Categories.CategoryID = Products.CategoryID  and ProductID <5

WHERE Categories.CategoryID <3  FOR XML AUTO

返回结果:

<Products ProductID="1" ProductName="Chai">

         <Categories CategoryID="1" CategoryName="Beverages"/>

</Products>

         <Products ProductID="2" ProductName="Chang">

         <Categories CategoryID="1" CategoryName="Beverages"/>

</Products>

<Products ProductID="3" ProductName="Aniseed Syrup">

         <Categories CategoryID="2" CategoryName="Condiments"/>

</Products>

<Products ProductID="4" ProductName="Chef Anton&apos;s Cajun Seasoning">

         <Categories CategoryID="2" CategoryName="Condiments"/>

</Products>

3.使用ELEMENTS选项

使用该选项可以生成以元素为中心的Xml表示,默认为属性方式,不过属性方式节省空间。需要注意的是使用ELEMENTS选项是一种全是或全否的形式,不能得到一部分是以元素表示而另一部分以属性表示的Xml数据。

查询语句:

SELECT CategoryID,

CategoryName

FROM Categories

WHERE CategoryID < 3

FOR XML AUTO, ELEMENTS

返回结果:

<Categories>

         <CategoryID>1</CategoryID>

         <CategoryName>Beverages</CategoryName>

</Categories>

<Categories>

         <CategoryID>2</CategoryID>

         <CategoryName>Condiments</CategoryName>

</Categories>

在连接查询时,

查询语句:

SELECT Categories.CategoryID,

ProductID,

ProductName

FROM Categories 

JOIN Products ON Categories.CategoryID = Products.CategoryID  and ProductID <4

WHERE Categories.CategoryID <3  FOR XML AUTO, ELEMENTS

返回结果:

<Categories>

         <CategoryID>1</CategoryID>

         <Products>

<ProductID>1</ProductID>

                   <ProductName>Chai</ProductName>

         </Products>

         <Products>

                   <ProductID>2</ProductID>

                   <ProductName>Chang</ProductName>

         </Products>

</Categories>

<Categories>

         <CategoryID>2</CategoryID>

         <Products>

                   <ProductID>3</ProductID>

                   <ProductName>Aniseed Syrup</ProductName>

         </Products>

</Categories>

4.检索对二进制数据的XPath引用

这是对二进制数据的操作,

查询语句:

SELECT CategoryID,

Picture

FROM Categories

WHERE CategoryID = 1

FOR XML AUTO

返回结果:

<Categories CategoryID="1" Picture="dbobject/Categories[@CategoryID='1']/@Picture"/>

使用ELEMENTS方式,

查询语句:

SELECT CategoryID,

Picture

FROM Categories

WHERE CategoryID = 1

FOR XML AUTO,ELEMENTS

返回结果:

<Categories>

         <CategoryID>1</CategoryID>

         <Picture>dbobject/Categories[@CategoryID='1']/@Picture</Picture>

</Categories>

 

二.使用RAW模式

使用RAW模式不能使用ELEMENTS选项。

1.简单查询

查询语句:

SELECT CategoryID,

CategoryName AS Nanme

FROM Categories

WHERE CategoryID < 3

ORDER BY CategoryID DESC

FOR XML RAW

返回结果:

<row CategoryID="2" Nanme="Condiments"/>

<row CategoryID="1" Nanme="Beverages"/>

2.连接查询

查询语句:

SELECT Categories.CategoryID,

Categories.CategoryName,

ProductID,

ProductName

FROM Categories 

JOIN Products ON Categories.CategoryID = Products.CategoryID  and ProductID <4

WHERE Categories.CategoryID <= 2  FOR XML RAW

返回结果:

<row CategoryID="1" CategoryName="Beverages" ProductID="1" ProductName="Chai"/>

<row CategoryID="1" CategoryName="Beverages" ProductID="2" ProductName="Chang"/>

<row CategoryID="2" CategoryName="Condiments" ProductID="3" ProductName="Aniseed Syrup"/>

 

三.使用EXPLICIT模式

该模式使用起来相对比较复杂,不过它可以很灵活的控制返回的xml数据结构。在该查询中定义了两个表示元数据的额外列。Tag列唯一的确定用来在结果中表示每一行的xml标记,Parent列用来控制元素之间的嵌套关系。

1.使用通用表

EXPLICIT模式下有一个通用表的概念,使用数据列的名称来定义xml文档中的数据。结构如下:

ElementName!TagNumber!AttributeName!Directive

下面的说明来自联机丛书,

ElementName

是所得到的元素类属标识符(例如,如果将 Customers 指定为ElementName,则 <Customers> 是元素标记)。

TagNumber

是元素的标记号。借助于通用表中的两个元数据列(Tag Parent),TagNumber用于表示 XML 树中的 XML 元素嵌套。每个TagNumber都准确对应于一个ElementName

AttributeName

XML 特性的名称(如果没有指定Directive)或包含的元素名(如果Directive xmlcdata element)。如果指定Directive,则AttributeName可以为空。这种情况下,列中包含的值直接由具有指定ElementName的元素所包含。

Directive

是可选命令。如果没有指定Directive,则必须指定AttributeName。如果没有指定AttributeName且没有指定Directive(如 Customer!1),则表示元素命令(如 Customer!1!!element)且包含数据。

Directive有两种用途。该选项用于分别使用关键字 IDIDREF IDREFS IDIDREF IDREFS 进行编码。还用于表示如何使用关键字 hideelementxmlxmltext cdata 将字符串数据映射到 XML。大多数情况下允许在这些组中组合指令,但是不能在组本身中进行组合。

ID

可将元素特性指定为 ID 类型的特性。然后可以使用 IDREF IDREFS 特性引用它们,以启用文档内的链接。但是,如果没有请求 XMLDATA,则此关键字无效。

IDREF

指定为 IDREF 的特性可用于引用 ID 类型的特性,以启用文档内的链接。但是,如果没有请求 XMLDATA,则此关键字无效。

IDREFS

指定为 IDREFS 的特性可用于引用 ID 类型的特性,以启用文档内的链接。但是,如果没有请求 XMLDATA,则此关键字无效。

hide

不显示特性。这对于按照不出现在结果中的特性对结果进行排序可能很有用。

element

不生成特性。而是生成具有指定名称的包含元素(如果没有指定特性名则直接生成包含元素)。包含数据被编码为实体(例如,字符 < 变成 &lt;)。该关键字可以与 IDIDREF IDREFS 组合。

xml

除了不进行实体编码外,该命令与元素命令相同(例如,字符 < 仍是 <)。除了 hide 外,该命令不能与任何其它命令一起使用。

xmltext

列内容应包在单个标记内,以便与文档的其它部分集成。如果指定了AttributeName,则标记名由指定名称替换;否则通过将内容放在容器的起始处而不进行实体编码,将特性追加到包含元素的当前特性列表。含有该命令的列必须是文本类型(varcharnvarcharcharnchartextntext)。该命令只能与 hide 一起使用。在提取存储在列中的溢出数据时该命令很有用。 如果内容不是有效的 XML,则该行为不明确。

cdata

通过用 CDATA 节环绕数据来包含数据。不对内容进行实体编码。原始数据类型必须是文本类型(varcharnvarchartextntext)。该命令只能与 hide 一起使用。当使用该命令时,不应指定AttributeName

2.简单查询

在指定数据所在的元素的名称和标记时必须使用ElementName参数和Tag参数,也就是查询语句中表中存在的每一个实际的数据列都必须以ElementName!Tag开头。在没有指定AttributeName!Directive的情况下以元素值的形式返回。在只查询一个表的情况下Tag1ParentNULL

使用EXPLICIT模式来查询数据我认为使用倒推的方式会比较方便一些,比如我要得到如下结构,

<Category ID=CategoryID Name=CategoryName>Description</Category>

查询语句:

SELECT 1 AS Tag,NULL AS Parent,

CategoryID AS [Category!1!ID],

CategoryName AS [Category!1!Name],

Description AS [Category!1]

FROM Categories

WHERE categoryID > 6 FOR XML EXPLICIT

返回结果:

<Category ID="7" Name="Produce">Dried fruit and bean curd</Category>

<Category ID="8" Name="Seafood">Seaweed and fish</Category>

当然下面的语句同上面的等效,

SELECT 1 Tag,NULL Parent,

CategoryID  [Category!1!ID],

CategoryName  [Category!1!Name],

Description  [Category!1]

FROM Categories

WHERE categoryID > 6 FOR XML EXPLICIT

2.连接查询

EXPLICIT模式下的多表连接查询可能相对比较复杂些,先来看一个简单的例子,

查询语句:

SELECT 1 AS Tag,NULL AS Parent,

Categories.CategoryID AS [Category!1!ID],

Categories.CategoryName AS [Category!1!!element],

ProductID  AS [Category!1!ProductID!element],

ProductName AS  [Category!1!ProductName!element]

FROM Categories 

JOIN Products ON Categories.CategoryID = Products.CategoryID AND ProductID <5

WHERE Categories.CategoryID < 3 FOR XML EXPLICIT

返回结果:

<Category ID="1">

         Beverages

         <ProductID>1</ProductID>

         <ProductName>Chai</ProductName>

</Category>

<Category ID="1">

         Beverages

         <ProductID>2</ProductID>

         <ProductName>Chang</ProductName>

</Category>

<Category ID="2">

         Condiments

         <ProductID>3</ProductID>

         <ProductName>Aniseed Syrup</ProductName>

</Category>

<Category ID="2">

         Condiments

         <ProductID>4</ProductID>

         <ProductName>Chef Anton&apos;s Cajun Seasoning</ProductName>

</Category>

从上面的结构可以看出数据的xml结构不是很舒服,存在比较大的冗余。想象中改进后的结构如下:

<Category ID="2" Name="Condiments">

         <Product>

                   <ProductID>3</ProductID>

                   <ProductName>Aniseed Syrup</ProductName>

         </Product>

         <Product>

                   <ProductID>4</ProductID>

                   <ProductName>Chef Anton&apos;s Cajun Seasoning</ProductName>

         </Product>

</Category>

<Category ID="1" Name="Beverages">

         <Product>

                   <ProductID>1</ProductID>

                   <ProductName>Chai</ProductName>

         </Product>

         <Product>

                   <ProductID>2</ProductID>

                   <ProductName>Chang</ProductName>

         </Product>

</Category>

从上面看出Category元素的Tag1ParentNULL,而Product元素的Tag2Parent1(即CategoryTag值)。这里有一个问题需要解决,那就是在TagParent中存在两套值,这里就需要使用UNION ALL运算符来实现这项功能,UNION ALL运算符的一项功能就是消除查询返回的重复的行。使用UNION ALL时需要注意的是结果集的列数必须相同。

查询语句:

SELECT 1 AS Tag,NULL AS Parent,

CategoryID AS [Category!1!ID],

CategoryName AS [Category!1!Name],

NULL  AS [Product!2!ProductID!element],

NULL  AS [Product!2!ProductName!element]

FROM Categories  WHERE CategoryID < 3

UNION ALL

SELECT 2 AS Tag,1 AS Parent,

Categories.CategoryID AS [Category!1!ID],

Categories.CategoryName AS [Category!1!Name],--这里可以使用NULL代替

ProductID  AS [Product!2!ProductID!element],

ProductName  AS [Product!2!ProductName!element]

FROM Categories

JOIN Products ON Categories.CategoryID = Products.CategoryID AND ProductID <5

WHERE Categories.CategoryID < 3

ORDER BY [Category!1!ID] DESC,[Product!2!ProductID!element] ASC

FOR XML EXPLICIT

返回结果:

<Category ID="2" Name="Condiments">

         <Product>

                   <ProductID>3</ProductID>

                   <ProductName>Aniseed Syrup</ProductName>

         </Product>

         <Product>

                   <ProductID>4</ProductID>

                   <ProductName>Chef Anton&apos;s Cajun Seasoning</ProductName>

         </Product>

</Category>

<Category ID="1" Name="Beverages">

         <Product>

                   <ProductID>1</ProductID>

            &n