XML 在SQLServer中的使用
SQL Server对于XML支持的核心在于XML数据的格式,这种数据类型可以将XML的数据存储于数据库的对象中,比如variables, columns, and parameters。当你用XML数据类型配置这些对象中的一个时,你指定类型的名字就像你在SQLServer 中指定一个类型一样。
XML的数据类型确保了你的XML数据被完好的构建保存,同时也符合ISO的标准。在定义一个XML数据类型之前,我们首先要知道它的几种限制,如下:
- 一个实例的XML列不能包含超过2GB的数据。
- 一个XML的列不能是索引。
- XML对象不能使用Group By的子句中。
- XML的数据类型不支持比较和排序。
定义一个XML变量
DECLARE @ClientList XML
SET @ClientList =
'<?xml version="1.0" encoding="UTF-8"?>
<!-- A list of current clients -->
<People>
<Person id="1234">
<FirstName>John</FirstName>
<LastName>Doe</LastName>
</Person>
<Person id="5678">
<FirstName>Jane</FirstName>
<LastName>Doe</LastName>
</Person>
</People>'
SELECT @ClientList
GO
这个例子通过使用DECLARE 声明去定义名为@ClientList 的变量,当我声明变量的时候,只需要包含XML的数据类型的名字在变量名后。
我设定了变量的值,然后使用select 来检索这个值。和我们想的一样,它返回了XML的文档。如下:
<!-- A list of current clients -->
<People>
<Person id="1234">
<FirstName>John</FirstName>
<LastName>Doe</LastName>
</Person>
<Person id="5678">
<FirstName>Jane</FirstName>
<LastName>Doe</LastName>
</Person>
</People>
接下来我们看看如何定义一个XML的列
在下面的例子中,我将创建一个商店客户的表,表中存储了ID和每个商店的客户信息。
USE AdventureWorks2008R2
GO
IF OBJECT_ID('dbo.StoreClients') IS NOT NULL
DROP TABLE dbo.StoreClients
GO
CREATE TABLE dbo.StoreClients
(
StoreID INT IDENTITY PRIMARY KEY,
ClientInfo XML NOT NULL
)
GO
接下来插入数据到这个表中,包括XML的文档和片段。我将声明一个XML的变量,然后用这个变量插入这个文档到表的数据行里面。
DECLARE @ClientList XML
SET @ClientList =
'<?xml version="1.0" encoding="UTF-8"?>
<!-- A list of current clients -->
<People>
<Person id="1234">
<FirstName>John</FirstName>
<LastName>Doe</LastName>
</Person>
<Person id="5678">
<FirstName>Jane</FirstName>
<LastName>Doe</LastName>
</Person>
</People>'
INSERT INTO dbo.StoreClients (ClientInfo)
VALUES(@ClientList)
GO
尽管变量将整个XML文档插入了进来,但是它是被当做一个单一的值插入到表列里面来。
正如以上所述,创建和插入都是很直接简单的,接下来我们看一下如何创建一个XML的参数
定义一个XML参数
例如,我定义@StoreClients 作为一个输入参数,并且配置它为XML的类型
USE AdventureWorks2008R2
GO
IF OBJECT_ID('dbo.AddClientInfo', 'P') IS NOT NULL
DROP PROCEDURE dbo.AddClientInfo
GO
CREATE PROCEDURE dbo.AddClientInfo
@StoreClients XML
AS
INSERT INTO dbo.StoreClients (ClientInfo)
VALUES(@StoreClients)
GO
然后我们再看看在存储过程中如何使用XML作为参数:
DECLARE @ClientList XML
SET @ClientList =
'<?xml version="1.0" encoding="UTF-8"?>
<!-- A list of current clients -->
<People>
<Person id="1234">
<FirstName>John</FirstName>
<LastName>Doe</LastName>
</Person>
<Person id="5678">
<FirstName>Jane</FirstName>
<LastName>Doe</LastName>
</Person>
</People>'
EXEC dbo.AddClientInfo @ClientList
过程也是很直接,先将XML数据赋值给变量,然后将变量作为参数执行SP,这是查询你会发现数据已经在表中了。
现在我们要学习一下XML类型支持的方法:query(
)
, value().
在这之前我们要知道一种表达式,就是XQuery,它是一种强大的脚本语言,用来获取XML的数据。SQLServer 支持这种语言的子集,所以我们能使用这种语言的表达式来检索和修改XML的数据。
注意:
因为XQuery是一种非常复杂的语言,我们只是涉及了一部分他的组件,如果想要更进一步的理解它如何应用,请查看MSDN XQuery language reference.
那我们现在先来通过例子来看一下query()和value 两个方法是如何使用XML数据的。需要注意的是我接下来的测试环境是SQLServer2008 R2。实例中包含了ClientDB
数据库、ClientInfoCollection 的
XML数据以及ClientInfo
表。
USE master;
GO IF DB_ID('ClientDB') IS NOT NULL
DROP DATABASE ClientDB;
GO CREATE DATABASE ClientDB;
GO USE ClientDB;
GO IF OBJECT_ID('ClientInfoCollection') IS NOT NULL
DROP XML SCHEMA COLLECTION ClientInfoCollection;
GO CREATE XML SCHEMA COLLECTION ClientInfoCollection AS
'<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="urn:ClientInfoNamespace"
targetNamespace="urn:ClientInfoNamespace"
elementFormDefault="qualified">
<xsd:element name="People">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Person" minOccurs="1" maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="FirstName" type="xsd:string" minOccurs="1" maxOccurs="1" />
<xsd:element name="LastName" type="xsd:string" minOccurs="1" maxOccurs="1" />
<xsd:element name="FavoriteBook" type="xsd:string" minOccurs="0" maxOccurs="5" />
</xsd:sequence>
<xsd:attribute name="id" type="xsd:integer" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>';
GO IF OBJECT_ID('ClientInfo') IS NOT NULL
DROP TABLE ClientInfo;
GO CREATE TABLE ClientInfo
(
ClientID INT PRIMARY KEY IDENTITY,
Info_untyped XML,
Info_typed XML(ClientInfoCollection)
); INSERT INTO ClientInfo (Info_untyped, Info_typed)
VALUES
(
'<?xml version="1.0" encoding="UTF-8"?>
<People>
<Person id="1234">
<FirstName>John</FirstName>
<LastName>Doe</LastName>
</Person>
<Person id="5678">
<FirstName>Jane</FirstName>
<LastName>Doe</LastName>
</Person>
</People>',
'<?xml version="1.0" encoding="UTF-8"?>
<People xmlns="urn:ClientInfoNamespace">
<Person id="1234">
<FirstName>John</FirstName>
<LastName>Doe</LastName>
</Person>
<Person id="5678">
<FirstName>Jane</FirstName>
<LastName>Doe</LastName>
</Person>
</People>'
);
Listing 1: 创建测试环境和数据
The XML query() Method
query方法,通常被用来返回一个指定XML子集的无类型的XML实例,如下,用括号加单引号来实现表达式,语法:
db
_object
.query('
xquery_exp
')
当我们调用这个方法时,用真实数据库对象替换掉引号内的表达式。通过实例来比较一下结果有什么不一样。
SELECT Info_untyped.query('/People')
AS People_untyped
FROM ClientInfo;
Listing 2: 使用query(
)
来获得<People>元素中的值
在这种情况下,将返回标签下所有的元素,包括子元素属性以及它们的值。
<People>
<Person id="1234">
<FirstName>John</FirstName>
<LastName>Doe</LastName>
</Person>
<Person id="5678">
<FirstName>Jane</FirstName>
<LastName>Doe</LastName>
</Person>
</People>
Listing 3: 结果集返回了/People
的内容
假如打算检索类型化的列中的<People>
元素的内容,我需要修改XQuery的表达式。如Listing 4
SELECT Info_typed.query(
'declare namespace ns="urn:ClientInfoNamespace";
/ns:People') AS People_typed
FROM ClientInfo;
Listing 4: 使用query(
)
来检索类型化的XML列,然后你运行这个语句,就会得到结果如Listing5
<People xmlns="urn:ClientInfoNamespace">
<Person id="1234">
<FirstName>John</FirstName>
<LastName>Doe</LastName>
</Person>
<Person id="5678">
<FirstName>Jane</FirstName>
<LastName>Doe</LastName>
</Person>
</People>
Listing 5: 展示结果
如上,我们发现两种结果是很接近的,唯一的区别就是类型化的列里面包含了涉及的命名空间。
如果我们打算获得子下一级,子元素的内容,我们需要修改表达式,通过添加/Person
到路径名称中,如下:
SELECT
Info_untyped.query(
'/People/Person') AS People_untyped,
Info_typed.query(
'declare namespace ns="urn:ClientInfoNamespace";
/ns:People/ns:Person') AS People_typed
FROM ClientInfo;
Listing 6: 检索 <Person>
元素
<Person id="1234">
<FirstName>John</FirstName>
<LastName>Doe</LastName>
</Person>
<Person id="5678">
<FirstName>Jane</FirstName>
<LastName>Doe</LastName>
</Person>
Listing 7: 这个结果集是非类型化数据的结果
<ns:Person xmlns:ns="urn:ClientInfoNamespace" id="1234">
<ns:FirstName>John</ns:FirstName>
<ns:LastName>Doe</ns:LastName>
</ns:Person>
<ns:Person xmlns:ns="urn:ClientInfoNamespace" id="5678">
<ns:FirstName>Jane</ns:FirstName>
<ns:LastName>Doe</ns:LastName>
</ns:Person>
Listing 8: 这个结果集是类型化数据的结果
如果我们打算去得到指定的<Person>下面的某一个元素,需要加入涉及的id属性。下面对比类型和非类型的两种情况下指定元素属性时如何获取。
SELECT
Info_untyped.query(
'/People/Person[@id=1234]') AS People_untyped,
Info_typed.query(
'declare namespace ns="urn:ClientInfoNamespace";
/ns:People/ns:Person[@id=5678]') AS People_typed
FROM ClientInfo;
Listing 9: 检索数据,指定元素
前面的没有变化,按照元素来添加表达式,然后用中括号,在中括号内添加了@id的值,结果如下
<Person id="1234">
<FirstName>John</FirstName>
<LastName>Doe</LastName>
</Person>
Listing 10: id为1234非类型化数据结果返回值。
对于类型化的列,我使用的id为5678.注意,这次不再需要在属性名称前加上命名空间的前缀了,只需要在元素名字前引用就足够了。
<ns:Person xmlns:ns="urn:ClientInfoNamespace" id="5678">
<ns:FirstName>Jane</ns:FirstName>
<ns:LastName>Doe</ns:LastName>
</ns:Person>
Listing 11: id为5678的数据结果
更进一步的展示结果,向下一级
SELECT
Info_untyped.query(
'/People/Person[@id=1234]/FirstName') AS People_untyped,
Info_typed.query(
'declare namespace ns="urn:ClientInfoNamespace";
/ns:People/ns:Person[@id=5678]/ns:FirstName') AS People_typed
FROM ClientInfo;
结果
<FirstName>John</FirstName>
<ns:FirstName xmlns:ns="urn:ClientInfoNamespace">Jane</ns:FirstName>
Listing 14: 名字的结果的展示
当然还可以通过数字索引的方式展示:
SELECT
Info_untyped.query(
'/People/Person[1]/FirstName') AS People_untyped,
Info_typed.query(
'declare namespace ns="urn:ClientInfoNamespace";
/ns:People/ns:Person[2]/ns:FirstName') AS People_typed
FROM ClientInfo;
Listing 15: 使用数字索引来引用元素下的结果
XML的value()方法
就如同query()方法一样简便,很多时候当你想去检索一个特定的元素或属性的时候,而不是获取XML的元素,那就可以使用value()了。这种方法只会返回一个特定的值,不作为数据类型。因此一定要传递两个参数XQuery表达式和T-SQL数据类型。下面看语法:
db
_object
.value('
xquery_exp
', '
sql_type
')
SELECT
Info_untyped.value(
'(/People/Person[1]/FirstName)[1]',
'varchar(20)') AS Name_untyped,
Info_typed.value(
'declare namespace ns="urn:ClientInfoNamespace";
(/ns:People/ns:Person[2]/ns:FirstName)[1]',
'varchar(20)') AS Name_typed
FROM ClientInfo;
Listing 16: 检索<FirstName>
的值
在Listing16中,我指定了[1]在Xquery表达式的后面,所以结果集将只返回第一个人的名字。
Name_untyped Name_typed
-------------------- --------------------
John Jane
Listing 17: <FirstName>的两个结果
当然,我们也可以检索每个实例的id的属性值,并且指定Int类型返回。
SELECT
Info_untyped.value(
'(/People/Person/@id)[1]',
'int') AS Name_untyped,
Info_typed.value(
'declare namespace ns="urn:ClientInfoNamespace";
(/ns:People/ns:Person/@id)[2]',
'int') AS Name_typed
FROM ClientInfo;
Listing 19: 检索两个实例的id属性值
Name_untyped Name_typed
-------------------- --------------------
1234 5678
Listing 20: 返回两个id的属性
除了在表达式中定义你的XQuery表达式,你也能聚合的功能来进一步定义你的查询和操作数据。例如,count()功能,我们来获取每个列中<Person>
元素的个数。
SELECT
Info_untyped.value(
'count(/People/Person)',
'int') AS Number_untyped,
Info_typed.value(
'declare namespace ns="urn:ClientInfoNamespace";
count(/ns:People/ns:Person)',
'int') AS Number_typed
FROM ClientInfo;
Listing 21: 使用count功能来检索元素个数
结果如下:
Number_untyped Number_typed
-------------- ------------
2 2
Listing 22: 每列数据中<Person>
元素的数量
另外一个常用的功能是concat(
)
, 它可以连接两个或多个XML元素下的数据。你可以指定你想连接的每一个部分。示例:
SELECT
Info_untyped.value(
'concat((/People/Person/FirstName)[2], " ",
(/People/Person/LastName)[2])',
'varchar(25)') AS FullName
FROM ClientInfo;
Listing 23: 使用concat(
)来连接数值
FullName
-------------------------
Jane Doe
Listing 24: 连接后的返回值
名和姓被连接起来,组成一个单一的值。都来自于同一个<Person>
下,当然也可以来自不同。
总结
我们基本上了解了XML在SQLServer 中的简单应用,从定义到使用方法。也看到了query()检索子集,也能使用value()检索独立的元素属性的值。当然除此之外还有向exist(
)
andnodes()
这样方法,配合语法都以应用,这部分就不再展开讲了,大同小异。有不明白的可以私聊。更多使用方法还请访问MSDN来获取(搜索XQuery language reference)。
XML 在SQLServer中的使用的更多相关文章
- 我是如何在SQLServer中处理每天四亿三千万记录的
首先声明,我只是个程序员,不是专业的DBA,以下这篇文章是从一个问题的解决过程去写的,而不是一开始就给大家一个正确的结果,如果文中有不对的地方,请各位数据库大牛给予指正,以便我能够更好的处理此次业务. ...
- SQLSERVER中的假脱机spool
SQLSERVER中的假脱机spool 我发现网上对于假脱机的解释都非常零散,究竟假脱机是什么? 这几天在家里研究了一下,收集了很多网上的资料 假脱机是中文的翻译,而英文的名字叫做 spool 在徐老 ...
- 【转】我是如何在SQLServer中处理每天四亿三千万记录的
原文转自:http://blog.jobbole.com/80395/ 首先声明,我只是个程序员,不是专业的DBA,以下这篇文章是从一个问题的解决过程去写的,而不是一开始就给大家一个正确的结果,如果文 ...
- SQLServer中的死锁的介绍
简介 什么是死锁? 我认为,死锁是由于两个对象在拥有一份资源的情况下申请另一份资源,而另一份资源恰好又是这两对象正持有的,导致两对象无法完成操作,且所持资源无法释放. 什么又是阻塞? 阻塞是 ...
- [转]在SqlServer 中解析JSON数据
在Sqlserver中可以直接处理Xml格式的数据,但因为项目需要所以要保存JSON格式的数据到Sqlserver中在博客:Consuming JSON Strings in SQL Server ...
- 如何在SQLServer中处理每天四亿三千万记录
首先声明,我只是个程序员,不是专业的DBA,以下这篇文章是从一个问题的解决过程去写的,而不是一开始就给大家一个正确的结果,如果文中有不对的地方,请各位数据库大牛给予指正,以便我能够更好的处理此次业务. ...
- (转)SqlServer中处理每天四亿三千万记录的
项目背景 这是给某数据中心做的一个项目,项目难度之大令人发指,这个项目真正的让我感觉到了,商场如战场,而我只是其中的一个小兵,太多的战术,太多的高层之间的较量,太多的内幕了.具体这个项目的情况,我有空 ...
- (转)我是如何在SQLServer中处理每天四亿三千万记录的
首先声明,我只是个程序员,不是专业的DBA,以下这篇文章是从一个问题的解决过程去写的,而不是一开始就给大家一个正确的结果,如果文中有不对的地方,请各位数据库大牛给予指正,以便我能够更好的处理此次业务. ...
- SQLServer 中实现类似MySQL中的group_concat函数的功能
SQLServer中没有MySQL中的group_concat函数,可以把分组的数据连接在一起. 后在网上查找,找到了可以实现此功能的方法,特此记录下. SELECT a, stuff((SELECT ...
随机推荐
- csharp: DataRelation objects to represent a parent/child/Level relationship
/// <summary> /// /// </summary> /// <param name="sender"></param> ...
- MEF入门之不求甚解,但力求简单能讲明白(四)
上一篇我们已经可以获取各种FileHandler的实例和对应的元数据.本篇,我们做一个稍微完整的文件管理器. 1.修改接口IFileHandler,传入文件名 namespace IPart { pu ...
- Calling startActivity() from outside of an Activity
在Activity中使用startActivity()方法不会有任何限制,因为Activity重载了Context的startActivity()方法.但是如果是在其他地方(如Widget或Servi ...
- Android使用SAX解析XML(6)
应用截图: (1)开始运行时 (2)选择学院 (3)选择专业 (4)选择班级 (5)选择班级的详细信息 本文参考了<Android平台开发之旅>.
- Java基础复习笔记系列 五 常用类
Java基础复习笔记系列之 常用类 1.String类介绍. 首先看类所属的包:java.lang.String类. 再看它的构造方法: 2. String s1 = “hello”: String ...
- Scalaz(10)- Monad:就是一种函数式编程模式-a design pattern
Monad typeclass不是一种类型,而是一种程序设计模式(design pattern),是泛函编程中最重要的编程概念,因而很多行内人把FP又称为Monadic Programming.这其中 ...
- Yii2.0学习笔记:创建登录表单
第一步:在model层创建一个EntryForm.php文件 复制以下代码,注意model的文件.方法.类的命名规范(大小写) <?php namespace app\models; use Y ...
- Jmeter常用函数之__CSVRead使用
__CSVRead函数用于对脚本进行参数话,当脚本中不同变量需要不同参数值时,可以考虑__CSVRead函数. 以登录的用户名.密码为例:实际进行压力测试时,需要模拟使用不同的用户并发访问系统,此时需 ...
- zDialog 可拖拽弹出层
zDialog弹出框: 代替window.open.window.alert.window.confirm:提供良好的用户体验: 水晶质感,设计细腻,外观漂亮: 兼容ie6/7/8.firefox2/ ...
- 小谈React、React Native、React Web
React有三个东西,React JS 前端Web框架,React Native 移动终端Hybrid框架,React Web是一个源码转换工具(React Native 转 Web,并之所以特别提出 ...