水滴石穿

渴望成为高手--Amy.Qiu
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

SQL Server2005 XML数据类型基础

Posted on 2009-04-14 14:45  AmyQiu  阅读(248)  评论(0编辑  收藏  举报

SQL Server 2005XmL数据类型基础

一、引言

XML数据类型,可使用XML作为表和视图中的列,可用于T-SQL语句中或作为存储过程的参数。

可以直接在数据库中存储、查询和管理XML文件。还能规定你的XML必须遵从的模式。

 

SQL Server 2005中,除了提供机制以校验你的数据库中的XML类型之外,

它还允许你描述要被存储的复杂数据类型并且提供一个引擎来强制施加这些规则。

 

二、使用XML数据类型

 

XML数据类型与其它数据类型并不存在根本的区别。可以用在使用任何普通SQL数据类型的地方。

例:DECLARE @doc xml

SELECT @doc = '<Team name="Braves" />'

另外,你还可以使用一个查询和SQL ServerFOR XML语法来填充一个XML变量:

SELECT @doc =

(SELECT * FROM Team FOR XML AUTO)

XML数据类型不仅可以作为变量使用,也可以应用于表列中。还能分配缺省值并且支持NOT NULL约束:

CREATE TABLE Team

(

TeamID int identity not null,

TeamDoc xml DEFAULT '<Team />' NOT NULL

)

XML数据插入到表格中只需要用字符串形式的XML指定即可。

INSERT INTO Team (TeamDoc)

VALUES ('

<Team name="Braves">

<Players>

<Pitcher name="John Smoltz"  role="Closer"/>

</Players>

</Team>');

 

三、XML数据类型的限制

 

·XML类型不能转换成textntext数据类型。

·除了string类型,没有其它数据类型能够转换成XML

·XML列不能应用于GROUP BY语句中。

·分布式局部(partitioned)视图不能包含XML数据类型。

·sql_variant实例的使用不能把XML作为一种子类型。

·XML列不能成为主键或外键的一部分。

·XML列不能指定为唯一的。

·COLLATE子句不能被使用在XML列上。

·XML列不能加入到规则中。

·唯一可应用于XML列的内置标量函数是ISNULLCOALESCE。没有其它内置标量函数支持使用XML类型。

·表中最多只能拥有个XML列。

·具有XML列的表不能有一个超过列的主键。

·具有XML列的表不能有一个timestamp数据类型作为它们的主键的一部分。

·存储在数据库中的XML仅支持级的层次。

 

四、XML类型方法

 

XML数据类型仅能用作一种blob类型数据,但是这正是XML数据类型显示其自身力量的地方。

XML数据类型支持使用UDT(myXml.operation())语法进行调用的若干方法。

 

XML数据类型方法:

query  执行一个XML查询并且返回查询的结果,结果是一个XML数据类型对象

exists 执行一个XML查询,并且如果有结果的话返回值

value  计算一个查询以从XML中返回一个简单的值

modify XML文档的适当位置执行一个修改操作

nodes  允许你把XML分解到一个表结构中

 

例:

CREATE TABLE Team

(

TeamID int identity not null,

TeamDoc xml DEFAULT '<Team />' NOT NULL

)

 

INSERT INTO Team

VALUES('<Team name="Braves">

<Players>

<Pitcher name="John Smoltz" role="Closer"/>

<Pitcher name="Russ Ortiz" role="Starter" />

<ThirdBase name="Chipper Jones" role="Starter" bats="switch"/>

</Players>

</Team>')

 

1. query方法

 

指定一个要计算的XqueryXPath表达式,该方法的结果是一个XML数据类型对象。语法如下:

query(XQuery)第一个参数总是一个Xquery表达式。    

 

SELECT TeamDoc.query('/Team/Players/Pitcher')

FROM Team

这个语句产生如下结果:

----------------------------------------------

<Pitcher name="John Smoltz" role="Closer" /><Pitcher name="Russ Ortiz" role="Starter" />

(1 row(s) affected)

 

这个query方法允许你查询和返回与你指定的表达式相匹配的结点列表。

该方法的真正威力来自于XQuery语法。

 

2. exist方法

 

这个exist方法用于决定是否一个查询能够产生任何结果。语法形式如下:

exist(XQuery)

 

SELECT Count(*)

FROM Team

WHERE TeamDoc.exist(

'/Team/Players/Pitcher[@role="Starter"]') = 1

 

3. value方法

这个value方法用于查询XML并且返回一个原子值。语法如下:

value(XQuerydatatype)

 

借助于value方法,你可以从XML中得到单个标量值。

为此,你必须指定XQuery语句和你想要它返回的数据类型,

并且你可以返回除了XML数据类型外的任何数据类型。

--进行一次查询以得到单个值

 

SELECT TeamDoc.value(

'(/Team/Players/Pitcher/@name)[1]',

'nvarchar(max)')

AS FirstPitcher

FROM Team

 

FirstPitcher

------------------------------

John Smoltz

(1 row(s) affected)

 

注意,queryvalue方法之间的不同在于,query方法返回一个XML数据类型-它包含查询的结果;

value方法返回一个带有查询结果的非XML数据类型。

另外,value方法仅能返回单个值(或标量值)

如果你试图创建一个使用value方法返回多于一个值的XQuery表达式,你将得到一个错误。

 

4. modify方法

 

可即时地修改一个XML对象的一部分

不必仅为了修改而检索一个完整的XML文档。可以用一种结合方式-Modify方法

SQL Server 2005的新的XML数据修改语言(XML DML)

 

Modify方法的语法是:modify(<XMLDML>)

(1) XML Insert

XML Insert语法(需要指定你想怎样插入该XML,可选择的是intoafterbefore)

into子句把InsertExpression作为LocationExpression的一个孩子结点插入

可选子句as firstas last用于指定在该孩子结点中插入的位置。

beforeafter则指定是在LocationExpression的前面还是后面插入它

 

insert

InsertExpression (

{{as first | as last}

into | after | before} LocationExpression

)

 

DECLARE @doc xml

SELECT @doc = '<Team name="Braves">

<Players>

<Pitcher name="John Smoltz" role="Closer"/>

</Players>

</Team>'

SET @doc.modify('

insert <Pitcher name="Jaret Wright"/> as last

into (/Team/Players)[1]')

select @doc

 

(2) XML Update

 

UPDATE Team

SET TeamDoc.modify('

insert <Pitcher name="Jaret Wright"/> as last

into (/Team/Players)[1]')

WHERE TeamDoc.exist('/Team[@name="Braves"]') = 1 

 

(3) XML delete语句的语法很直接:

delete LocationExpression

 

这个LocationExpression指定要从XML数据中删除什么内容

 

SET @doc.modify('delete/Team/Player/Pitcher')

 

SET @doc.modify('

delete /Team/Players/Pitcher[@name="John Smoltz"]')

 

SET @doc.modify('

delete /Team/Players/Pitcher[

@name="John Smoltz"]/@role')

 

(4) replace value语句描述了对XML数据的修改。语法如下:

replace value of

OriginalExpression

with

ReplacementValue | if

 

这个replace value语句用来修改在XML中的值。唯一可能的值是一个标签的内容或一个属性的值。

这个OriginalExpression必须解析为单个结点或属性。

这个ReplacementValue通常是一个要代替的值。

代替一个结点的内容要求使用text()函数的XQuery表达式来指定你想代替一个结点的文本。

 

DECLARE @doc xml

SELECT @doc = '

<Team name="Braves">

<Players>

<Pitcher name="John Smoltz" role="Closer">

With team since 1989

</Pitcher>

</Players>

</Team>'

SET @doc.modify('

replace value of (/Team/Players/Pitcher[

@name="John Smoltz"]/text())[1]

with "May start in 2005"')

 

修改属性是直接的,你只需要使用XQuery表达式来解析单个属性

 

SET @doc.modify('

replace value of (/Team/Players/Pitcher[

@name="John Smoltz"]/@role)[1]

with "Starter"')

 

replace value语法也支持条件替换,这可以通过在replace value语句的with子句内使用

ifthenelse语法实现。例如,如果John Smoltz是一个Closer的话,把他的role替换为Starter

但是如果他不是一个Starter的话,则把role属性修改为Closer

 

SET @doc.modify('

replace value of (/Team/Players/Pitcher[

@name="John Smoltz"]/@role)[1]

with (

if (/Team/Players/Pitcher[

@name="John Smoltz"]/@role = "Closer") then

"Starter"

else "Closer")')

 

5. nodes方法

nodes方法用于把一组由一个查询返回的结点转换成一个类似于结果集的表中的一组记录行。语法:

nodes (XQuery) Table(Column)

 

这里,XQuery是选择要暴露为一个结果集的结点的表达式。

TableColumn用于指定结果集中的名字。

注意,你仅可以操作一列并且它的自动类型为XML

 

DECLARE @doc xml

SELECT @doc = '

<Team name="Braves">

<Players>

<Pitcher name="John Smoltz" role="Closer">

With team since 1989

</Pitcher>

</Players>

</Team>'

SELECT Team.player.query('.') as Pitcher

FROM @doc.nodes('/Team/Players/Pitcher')

Team(player)

 

Pitcher

--------------------------------------------

<Pitcher name="John Smoltz" role="Closer">

With team since 1989

</Pitcher>

(1 row(s) affected)

 

注意,上面你使用了query方法把这些结点返回到结果中。其原因在于,

一个nodes方法的结果可能仅能为XML方法(查询,修改,删除和更新)IS NULLIS NOT NULL语句所参考。

 

一般地,你可以使用nodes方法把XML分解为一组更为有用的结果:

DECLARE @doc xml

SELECT @doc = '

<Team name="Braves">

<Players>

<Pitcher name="John Smoltz" role="Closer">

With team since 1989

</Pitcher>

</Players>

</Team>'

SELECT Team.player.value(

'./@name', 'nvarchar(10)') as Name,

Team.player.value('./@role', 'nvarchar(10)') as

PlayerRole

FROM @doc.nodes('/Team/Players/Pitcher')

Team(player)

 

这会产生如下的结果:

 

Name PlayerRole

--------------- ---------------

John Smoltz Closer

(1 row(s) affected)