使用Microsoft SQL Server 2000的XML查询
郑佐 2005-6-28
由于XML本身的诸多优点,XML技术已被广泛的使用,目前的好多软件技术同XML紧密相关,比如微软的.net 平台对xml提供了强大的支持,提供System.Xml以及其子命名空间下的类型来操作xml。Ado.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="
<MyTable ID="2" CategoryName="Condiments" CurrDate="
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'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是 xml、cdata 或 element)。如果指定Directive,则AttributeName可以为空。这种情况下,列中包含的值直接由具有指定ElementName的元素所包含。
Directive
是可选命令。如果没有指定Directive,则必须指定AttributeName。如果没有指定AttributeName且没有指定Directive(如 Customer!1),则表示元素命令(如 Customer!1!!element)且包含数据。
Directive有两种用途。该选项用于分别使用关键字 ID、IDREF 和 IDREFS 对 ID、IDREF 和 IDREFS 进行编码。还用于表示如何使用关键字 hide、element、xml、xmltext 和 cdata