SQL SERVER 2005 进行XML查询
1.
CREATE TABLE Team
(
TeamID int identity not null,
TeamDoc xml DEFAULT '<Team />' NOT NULL
)
query方法
注意:你可以在表和视图列、T-SQL语句或存储过程的参数中使用XML。
这个方法允许你指定一个要计算的Xquery或XPath表达式,该方法的结果是一个XML数据类型对象。它的具体语法形式如下:
第一个参数总是一个Xquery表达式。下面的例子使用一个查询来返回一个XML文档-其中包含有关每一个小组的投球手的信息:
这个语句产生如下结果:
CREATE TABLE Team
(
TeamID int identity not null,
TeamDoc xml DEFAULT '<Team />' NOT NULL
)
query方法
注意:你可以在表和视图列、T-SQL语句或存储过程的参数中使用XML。
这个方法允许你指定一个要计算的Xquery或XPath表达式,该方法的结果是一个XML数据类型对象。它的具体语法形式如下:
query(XQuery) |
第一个参数总是一个Xquery表达式。下面的例子使用一个查询来返回一个XML文档-其中包含有关每一个小组的投球手的信息:
SELECT TeamDoc.query('/Team/Players/Pitcher') FROM Team |
这个语句产生如下结果:
---------------------------------------------- <Pitcher name="John Smoltz" role="Closer" /> <Pitcher name="Russ Ortiz" role="Starter" /> (1 row(s) affected) |
exist方法
这个exist方法用于决定是否一个查询能够产生任何结果。这个exist方法的语法形式如下:
exist(XQuery) |
当你使用这个exist方法时,它计算这个XQuery查询,并且如果该查询产生任何结果的话返回值1。例如,下面语句查询小组表行中是否TeamDoc域中存有Starter投手:
--下面是简单的Exist语句:
SELECT Count(*) FROM Team WHERE TeamDoc.exist( '/Team/Players/Pitcher[@role="Starter"]') = 1 |
value方法
当你不想解释整个查询的结果而只想得到一个标量值时,这个value方法是很有帮助的。这个value方法用于查询XML并且返回一个原子值。这个value方法的语法如下:
value(XQuery,datatype) |
借助于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) |
注意,query和value方法之间的不同在于,query方法返回一个XML数据类型-它包含查询的结果;而value方法返回一个带有查询结果的非XML数据类型。另外,value方法仅能返回单个值(或标量值)。如果你试图创建一个使用value方法返回多于一个值的XQuery表达式,你将得到一个错误。
modify方法
尽管XQuery标准并没有提供一种更新XML的机制,但是SQL Server 2005提供了一种方法用于即时地修改一个XML对象的一部分。这意味着,你不必仅为了修改而检索一个完整的XML文档。为了即时修改一个文档,你可以采用一种结合方式-Modify方法和SQL Server 2005的新的XML数据修改语言(XML DML)。
Modify方法的语法是:
modify(<XMLDML>) |
该方法仅使用一个参数:XML DML语句。XML DML也类似于SQL的insert,update和delete语法,但是并不一样。例如,你可以通过使用insert DML语句来修改XML:
SET @doc.modify(' insert <Pitcher name="Jaret Wright"/> as last into (/Team/Players)[1] ') |
另外,你还可以通过调用一个UPDATE语句并修改一个XML列来实现同样目的:
--修改一个XML文档而不完全替换它:
UPDATE Team SET TeamDoc.modify(' insert <Pitcher name="Jaret Wright"/> as last into (/Team/Players)[1] ') WHERE TeamDoc.exist('/Team[@name="Braves"]') = 1 |
注意,在这个UPDATE语句中的SET子句并不遵循你过去编写SQL时所使用的SET x = y 模式。该语法假定,你能够提供一个完全新的值来代替旧值-这在XML情况下意味着要使用一个完全新的文档来代替旧文档。当使用XML类型时,Modify方法可以即时修改原始文档。也就是说,对于SQL Server来说,不必要对每一次修改都试图替换整个文档。在本例中的SET语法反映了一种即时修改一个文档的更为有效的方式。
共有三种XML DML语句:insert,update和delete。这三个语句分别用于插入,更新和删除一个XML对象的部分。每一个方法的语法类似于SQL,但是也有一些明显的差别。
下面是相应于insert语句的语法:
insert InsertExpression ( {{as first | as last} into | after | before} LocationExpression ) |
紧跟着这个insert语句的是你想要插入的XML(InsertExpression)。接下来,你需要指定你想怎样插入该XML。你的选择是into,after或before。其中,before和after子句指令数据库把InsertExpression作为LocationExpression的一个兄弟(sibling)插入。before或after则指定是在LocationExpression的前面还是后面插入它:
SET @doc.modify(' insert <Pitcher role="Starter" name="Jaret Wright"/> before (/Team/Players/Pitcher)[1] ') |
这个into子句把InsertExpression作为LocationExpression的一个孩子结点插入。可选子句as first和as last用于指定在该孩子结点中插入的位置:
--在小组内进行插入
SET @doc.modify(' insert <Pitcher role="Starter" name="Jaret Wright"/> into (/Team/Players)[1] ') |
--在小组内进行插入,指定它应该
--作为最后一个元素插入
SET @doc.modify(' insert <Pitcher role="Starter" name="Jaret Wright"/> as last into (/Team/Players)[1] ') |
delete语句的语法很直接:
delete LocationExpression |
这个LocationExpression指定要从XML数据中删除什么内容。例如,要删除所有的投球手:
SET @doc.modify('delete/Team/Player/Pitcher') |
因为查询指定所有的投球手元素,所以它们将被全部删除。如果你想仅删除一个元素,那么你可以指定标识属性。例如,为了仅删除投球手John Smoltz,你可以编写如下的delete语句:
SET @doc.modify(' delete /Team/Players/Pitcher[@name="John Smoltz"] ') |
你可以使delete语句删除单个属性。例如,为了删除针对投球手John Smoltz的role属性,相应的XML DML看上去如下所示:
SET @doc.modify(' delete /Team/Players/Pitcher[ @name="John Smoltz"]/@role') |
最后,replace value语句描述了对XML数据的修改。这个replace value语句的语法如下:
replace value of OriginalExpression with ReplacementValue | if |
这个replace value语句用来修改在XML中的值。唯一可能的值是一个标签的内容或一个属性的值。这个OriginalExpression必须解析为单个结点或属性。这个ReplacementValue通常是一个要代替的值。代替一个结点的内容要求使用text()函数的XQuery表达式来指定你想代替一个结点的文本。例如,为了替换一个投球手的内部文本(inner text),你可以编写类似如下的Modify语句:
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表达式来解析单个属性。例如,为了使用"Starter"替换投球手John Smoltz的role属性的值,你可以编写如下的语句:
SET @doc.modify(' replace value of (/Team/Players/Pitcher[ @name="John Smoltz"]/@role)[1] with "Starter" ') |
replace value语法也支持条件替换,这可以通过在replace value语句的with子句内使用if…then…else语法实现。例如,如果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" ) ') |
nodes方法
nodes方法用于把一组由一个查询返回的结点转换成一个类似于结果集的表中的一组记录行。该方法的语法如下:
nodes (XQuery) Table(Column) |
这里,XQuery是选择要暴露为一个结果集的结点的表达式。Table和Column用于指定结果集中的名字。注意,你仅可以操作一列并且它的自动类型为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" /> <Pitcher name="Russ Ortiz" role="Starter" /> (2 row(s) affected) |
注意,上面你使用了query方法把这些结点返回到结果中。其原因在于,一个nodes方法的结果可能仅能为XML方法(查询,修改,删除和更新)或IS NULL和IS NOT NULL语句所参考。
一般地,你可以使用nodes方法把XML分解为一组更为有用的结果。例如,你可以使用nodes方法得到运动员的结点,然后使用value方法检索它们以便得到作为标量数据的单个值:
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 Russ Ortiz Starter (2 row(s) affected) |