把Oracle数据库移植到Microsoft SQL Server 7.0
摘要:本文是为那些想把自己的Oracle应用程序转换为Microsoft SQL Server应用程序的开发人员编写的。本文描述了一个成功的转换所需要的工具、过程和技术。同时强调了建立高性能、高度并行的SQL Server应用程序的基本的设计要素。
本文的读者应该具有:
- Oracle关系型数据管理系统(RDBMS)的坚实基础。
- 普通数据库管理知识。
- 熟悉Oracle SQL和PL/SQL语言。
- C/C++编程语言的工作经验。
- 在sysadmin组中设定服务器规则的成员资格
本文假定你熟悉Oracle RDBMS的术语、概念和工具。如果想要了解关于Oracle RDBMS以及它的结构的更多信息,请参考Oracle 7 Server Concepts Manual。对于使用Oracle脚本和示例,仍然假定你熟悉Oracle Server Manager和Oracle SQL*Plus工具。要得到更详细的信息,请参看Oracle文档。
目录
- 开发和应用程序平台
- 概述
- 本文的组织形式
- 结构和术语
- 安装和配置Microsoft SQL Server
- 定义数据库对象
- 加强数据完整性和商业规则
- 事务、锁定和并行
- 死锁
- SQL语言支持
- 实现游标
- 调整SQL语句
- 使用ODBC
- 开发和管理数据库复制
- 移植你的数据和应用程序
- 数据库示例
开发和应用程序平台
为了便于清楚的表述,本文参照的开发和应用程序平台假定为Microsoft Visual Studio version 6.0、Microsoft Windows NT version 4 (Service Pack 4)、SQL Server 7.0、Oracle 7.3。Oracle 7.3使用Visigenic Software ODBC(版本2.00.0300)驱动,SQL Server 7.0使用Microsoft Corporation ODBC(版本3.70)驱动。Microsoft SQL Server 7.0包括针对Oracle的OLE DB驱动,但是该驱动程序在本章中并没有广泛的讨论。
概述
应用程序的移植似乎非常复杂。在不同的关系数据管理系统之间有太多的结构差异。用来描述Oracle结构的用词和术语通常与该词在Microsoft SQL Server中的意思完全不同。另外,Oracle和SQL Server都对SQL-92标准做了许多自有的扩展。
从一个应用程序开发人员的观点来看,Oracle和SQL Server是以相似的方法来管理数据的。在Oracle和SQL Server之间有着重大的内部区别,但是如果管理得当,可以把这些区别对移植的影响减到最小。
SQL语言扩展
开发人员面临的最重要的移植问题是执行SQL-92语言标准和每一个关系数据管理系统提供的语言扩展。有一些开发人员只使用标准的SQL语法,喜欢尽可能的保持他们的程序代码的普遍性。通常,这种方法把程序代码限制在SQL-92标准的登录级别(entry-level)上,而这个级别是被许多的数据库产品实现了的,包括Oracle和SQL Server。
这种方法将会产生一些不必要的程序代码复杂性而且还会对程序的性能造成很大的影响。例如,Oracle的DECODE函数是一个非标准的SQL扩展。Microsoft SQL Server的CASE表达式是一个超越了登录级别的SQL-92扩展,而且在所有其他的数据库产品中都没有实现。
Oracle的DECODE和SQL Server的CASE都是可选的,你可以不用这两个函数而实现它们的功能,而这需要从关系数据管理系统中提取更多的数据。
还有,对SQL语言的程序扩展也会造成困难。Oracle的PL/SQL和SQL Server的Transact-SQL语言在函数上是相似的,但是在语法上不同。在两种数据库和程序扩展中间没有明确的对称性。因此,你可能会决定不使用想程序和触发器这样的存储的程序。这是很不幸的,因为它们提供了别的任何方式都无法实现的性能和安全性上的优点。
私有开发接口的使用带来了新的问题。用Oracle OCI(Oracle Call Interface)进行程序转换通常需要很多资源。开发一个可能用到多个关系数据管理系统的应用程序,最好是考虑使用开放数据库连接(Open Database Connectivity,ODBC)接口。
ODBC
ODBC是为同多个数据库管理系统协同工作而设计的。ODBC提供了一个一致的应用程序编程接口(application programming interface,API),该接口使用一个针对数据库的驱动程序同不同的数据库协同工作。
一致的应用程序编程接口意味着程序用来建立连接、执行命令以及获取结果的函数是一样的,无论该程序是和Oracle还是SQL Server对话。
ODBC同时还定义了一个标准化的调用级别的接口并且针对那些不同数据库里完成同样任务但语法不同的SQL函数使用标准的出口次序。ODBC驱动器可以自动的把这个ODBC语法转化为Oracle或者SQL Server的本地语法,这个过程不需要对程序代码做任何的修订。在某些情况下,最好的方法是编写一个程序并且让ODBC在运行时间执行转换处理。
ODBC并不是一个万能的可以针对任何数据库实现完全独立的、完整功能和高性能的解决方案。不同数据库和第三方经销商提供了对ODBC不同级别的支持。一些驱动器仅仅实现了核心的API函数,这些函数映射了顶层或者其他接口库。其他一些驱动器,例如Microsoft SQL Server的驱动器,在一个本地的、高性能的驱动器中提供了完整的2级支持。
如果一个程序仅使用核心的ODBC API,它很可能会丢弃某些数据库的特征和性能。此外,并不是所有的本地SQL扩展都可以在ODBC出口次序中描述的(例如Oracle的DECODE和SQL Server的CASE表达式)。
另外,书写SQL语句来利用数据库优化器是意见很自然的事情。但是在Oracle中用来扩展数据库性能的技术和方法在Microsoft SQL Server 7.0中不一定是最好的。ODBC接口并不能把一个系统所用的技术翻译为另一个系统的技术。
ODBC并不影响一个应用程序使用数据库专有的特征和调整来提高性能,但是应用程序需要某些数据库专有的代码部分。ODBC使得在多个数据库间保持程序结构和多数程序代码一致变得容易。
OLE DB
OLE DB是下一代数据访问技术。Microsoft SQL Server 7.0利用包含在其自身的组件之中的OLE DB。这样,应用程序开发人员可以考虑使用OLE DB来进行新的SQL Server 7.0开发。微软在SQL Server 7.0中还提供了支持Oracle 7.3的OLE DB。
OLE DB是微软用来管理跨组织的数据的战略性的系统级编程接口。OLE DB是在ODBC特征上建立的具有开放性的设计。ODBC是设计来访问相关的数据库的,而OLE DB则是设计来访问相关的或者不相关的信息源,例如主机上的ISAM/VSAM和分层数据库,电子邮件和文件系统存储,文本、图像和地理数据以及定制的业务对象。
OLE DB了一组COM接口以压缩不同的数据库管理服务,同时还允许创建软件组件来实现这些服务.OLE DB组件包含了数据提供者(保持和显露数据)、数据消费者(使用数据)以及服务组件(处理和传输数据,例如查询处理器和光标引擎)。
OLE DB接口的设计目的是帮助实现组件的平滑集成,这样的话OLE DB组件提供商就可以迅速的向市场提供高质量的OLE DB组件了。此外、OLE DB还包含一座连接ODBC的桥梁,如此就可以为今天可以得到的大量的ODBC相关的数据库驱动程序继续提供支持了。
本文的组织方式
为了帮助你一步一步的实现从Oracle到SQL Server的转换,本文的每一部分都有一个关于Oracle7.3和Microsoft SQL Server 7.0的不同之处的概述。同时还包括转换的考虑,SQL Server 7.0的优势以及多个实例。
结构和术语
作为成功移植的开始,你应该掌握Microsoft SQL Server 7.0所用的基本的结构和术语。这一部分中的许多例子都是从本文包含的Oracle和SQL Server应用程序中截取下来的。
数据库的定义
在Oracle中,数据库是指整个Oracle RDBMS环境,并且包含以下组件。
Oracle数据库处理过程和数据缓存(实例)。
- 包含一个集中的系统目录的SYSTEM表空间。
- DBA定义的其它表空间(可选的)。
- 两个或者多个Redo日志。
- 存档的Redo日志(可选)
- 各种其它文件(控制文件、Init.ora等等)。
一个Microsoft SQL Server数据库提供了数据、应用程序以及安全机制的逻辑区分,更像一个表空间(tablespaces)。正如Oracle支持多个表空间,SQL Server也支持多个数据库。表空间也用来提供数据的物理放置,SQL Server通过文件组(filegroups)来提供同样的功能。
Microsoft SQL Server将缺省的安装下列数据库。
SQL Server同时在master数据库中保存一个集中系统目录,该目录包含系统目录和每个数据库的某些信息:
- 数据库名和每个数据库的初始文件位置。
- SQL Server登录账号。
- 系统消息。
- 数据库配置值。
- 远程和/或已连接的服务器。
- 当前活动信息。
- 系统存储过程。
像Oracle中的SYSTEM表空间一样,SQL Server的master数据库也必须能访问任何其他数据库。同样,对数据库做了任何重大的改变以后,通过备份master数据库来防止失败是很重要的。数据库管理员也应该能够为组成master数据库的文件做镜象。
物理和逻辑存储结构(Physical and Logical Storage Structures)
Oracle RDBMS是由表空间组成的,而表空间又是由数据文件组成的。表空间数据文件被格式化为内部的块单位。块的大小,是由DBA在Oracle第一次创建的时候设置的,可以在512到8192个字节的范围内变动。当一个对象在Oracle表空间中创建的时候,用户用叫做长度的单位(初始长度((initial extent)、下一个长度(next extent)、最小长度(min extents)、以及最大长度(max extents))来标明该对象的空间大小。一个Oracle长度的大小可以变化,但是要包含一个由至少五个连续的块构成的链。
Microsoft SQL Server在数据库级别使用文件组来控制表和索引的物理放置。文件组是一个或者多个文件的逻辑容器,一个文件组中的数据按比例填充属于该文件组的全部文件。
如果没有显明的定义和使用文件组,数据库对象将放置在一个缺省的文件组中,该文件组是在数据库的创建过程中隐含定义的。文件组允许你进行下列操作:
把大的表分布在多个文件中以提高I/O吞吐量。
把索引存储在不同的文件中,而不是放在各自的表中,再一次提高I/O吞吐量以及实现磁盘并行操作。
把text、ntext、和image columns(大对象)储存在一个表的不同文件中。
把数据库对象放置在特定的磁盘锭(disk spindles)上。
在一个文件组中备份和恢复个别表和表的设置。
SQL Server把文件格式化为叫做页(pages)的单位。页的大小固定为8192字节(即8K)。页按固定为8个连续页大小的格式组织为长度。当创建表或者索引时,SQL Server自动为其分配一页,比起分配一个长度来说,储存较小的表和索引,这种方法要更有效些。
标记数据(Striping Data)
(译注:Strip--在海量存储系统(MSS)中,可由给定磁头位置访问的数据盒式磁带中的那部分)
Oracle类型的段对于大多数Microsoft SQL Server安装来说都不需要。取而代之的是,SQL Server可以利用基于硬件的RAID或者Windows NT软件RAID来较好的完成数据的分布或者标记。基于硬件的RAID或者Windows NT软件RAID可以设置一个由多个硬盘组成的标记装置,使它们看起来就像一个逻辑驱动器一样。如果数据库文件是在这个标记装置上创建的,磁盘子系统就假定为负责通过多个磁盘来进行分布式的I/O装载。建议管理员使用RAID来将数据分布在多个物理磁盘上。
针对SQL Server的RAID推荐配置是RAID 1(镜象)或者RAID 5(拥有一个作为冗余的额外的驱动器的标记设备)。RAID 10(对有奇偶的标记设备的镜象)也是推荐的,但它比起前两个来要昂贵的多。标记设备在分散数据库文件上通常的随机I/O来说是很好的。
如果不能使用RAID,文件组就是一个很有吸引力的选择了,它提供了RAID可以提供的某些同样的好处。此外,对于那些可能跨越多个物理RAID阵列的非常大的数据库来说,文件组可能是一个很好的选择,它可以通过一种受控制的方式将I/O分布在多个RAID阵列上。
必须优化事务日志文件(Transaction log files),使之适应连续的I/O,并且必须保护该文件以防止单点失败。因此,建议采用RAID1(镜象)来做事务日志。该驱动器的大小至少应该和在线恢复日志(online redo logs)以及反转段表空间两者加起来的大小一样才行。创建一个或者更多个日志文件,把逻辑驱动器上定义的空间占满。和存储在文件组中的数据不同,事务日志条目总是按顺序写入的,而不是按比例填充的。
欲获得关于RAID的更多信息,请参看SQL Server联机图书,你的Windows NT服务器文档,以及Microsoft Windows NT资源指南。
事务日志和自动恢复(Transaction Logs and Automatic Recovery)
Oracle RDBMS在每次启动时执行自动修复。它检查表空间文件的目录与在线恢复日志文件中的目录是否一样。如果不一样,Oracle就使用在线恢复日志文件覆盖表空间文件(roll forward、前滚),然后去掉它在后滚段中发现的所有未完成的事务(roll back,后滚)。如果Oracle不能从在线恢复日志中得到需要的信息,则Oracle就求助于存档的恢复日志文件。
Microsoft SQL Server 7.0同样在每次启动时通过检查系统中的每个数据库来执行自动恢复。它首先检查master数据库,然后启动线程以覆盖系统中的所有数据库。对于每一个SQL Server数据库,自动修复机制将检查事务日志。如果事务日志中包含任何未完成的事务,则该事务后滚。然后自动修复机制再检查事务日志以找出那些还没有写入数据库的未完成事务。如果找到,则执行该事务,前滚。
SQL Server事务日志包含了Oracle后滚段和Oracle在线恢复日志两者总的功能。每个数据库都有自己的事务日志,该日志记录了数据库发生的任何改变,并且日志由数据库的所有用户共享。当一个事务开始并且发生一次数据修改,则一个BEGIN TRANSACTION事件(同modification事件一样)被记录在日志中。在自动恢复的过程中使用该事件来确定事务的起始点。每收到一个数据修改事件,改变都被记入事务日志中,优先写入其数据库中。欲了解更多信息,请参看本章后面的"事务、锁定和并行"部分。
SQL Server有一个自动检查点机制,该机制确保完成了的事务规则的从SQL Server磁盘缓存中写入事务日志文件。从数据库的上一个检查点算起,任何修改过的缓存页将被写入一个检查点。向数据库上的这些缓存页(dirty pages,污损页)写入检查点,确保了所有已完成的事务被写到磁盘上。该过程缩短了发生失败(例如能量损耗,power outage)时修复系统的所花的时间。该设置可以用SQL Server Enterprise Manager修改,还可以用Transact-SQL修改(sp_configure系统存储程序)。
备份和恢复数据
Microsoft SQL Server提供了几种备份数据的选择:
完全的数据库备份
要进行完全的数据库备份,使用BACKUP DATABASE语句或者"备份向导"(Backup Wizard)。
微分备份(Differential backup)
在经过完全的数据库备份以后,定期使用BACKUP DATABASE WITH DIFFERENTIAL语句或者"备份向导"来备份改变过的数据和索引页。
事务日志备份
Microsoft SQL Server中的事务日志有一个独立的数据库。该数据库仅在备份或者被删除以后才填充。SQL Server 7.0中的缺省设置是事务日志自动增长,直到它用完了所有的可用空间或者达到其设置的最大空间。当事务日志过满时,它会生成一个错误并且阻止任何的数据修改,直到该日志被备份或者被删除。其他的数据库不会受到影响。可以用BACKUP LOG语句或者"备份向导"进行事务日志备份。
文件或者文件组备份
SQL Server可以备份文件或者文件组。欲知详情,请参看SQL Server联机图书。
备份可以在数据库正在使用的时候进行,这样就可以使那些必须不断运行的系统进行备份。SQL Server 7.0的备份过程和数据结构已经大大的改进,可以使备份在对事务吞吐量影响最小的情况下达到最大的数据传输率。
Oracle和SQL Server都需要一个特殊的日志文件格式。在SQL Server中,这些叫做备份设备的文件是用SQL Server Enterprise Manager、Transact-SQL的sp_addumpdevice存储程序或者等价的SQL-DMO命令创建的。
虽然备份可以通过手工操作进行,但是建议你使用SQL Server Enterprise Manager和/或者"数据库维护计划向导"进行定期的备份,或者基于数据库活动进行备份。
应用事务日志备份和/或者微分备份,一个数据库可以按时储存在一个完全备份数据库(设备)的特定的点上。数据库使用备份中包含的信息恢复数据。可以用SQL Server Enterprise Manager、Transact-SQL (RESTORE DATABASE)或者SQL-DMO进行恢复。
就像你可以关掉Oracle存档器以跳过备份一样,在Microsoft SQL Server中,db_owner组中的成员可以强制事务日志在检查点发生的时候抹去目录。可以用SQL Server Enterprise Manager(删除检查点上的日志),Transact-SQL(sp_dboption存储过程)或者SQL-DMO来完成。
网络
Oracle SQL*Net支持Oracle数据库和其客户端的网络连接。它们通过透明网络层数据流协议进行通信,并且允许用户运行许多不同的网络协议,而不需要编写任何特殊的代码。SQL*Net未包含在核心Oracle数据库软件产品中。
在Microsoft SQL Server中,Net库(网络库)支持客户端和服务器的连接,它们通过列表数据流协议进行通信。这使得可以同时和运行名字管道(Named Pipes)、TCP/IP套接字或者其他交互处理机制(Inter-Process Communication、IPC)的客户端连接。SQL Server CD-ROM包含了所有的客户端Net库,不需要另外购买这些产品了。
SQL Server Net库选项可以在安装后修改。客户端网络工具为运行Windows NT、Windows 95、 或者Windows 98的客户端配置缺省的Net库和服务器连接信息。除非在ODBC数据源的安装过程中改变或者在ODBC连接字串中显式的标明,所有的ODBC客户端也使用同样的Net库和服务器连接信息。欲了解关于Net库的更多信息,请参看SQL Server联机手册。
数据库安全性和角色(Database Security and Roles)
为了把你的Oracle应用程序完整的移植到Microsoft SQL Server 7.0上,你需要明白SQL Server是如何实现数据库的安全性和角色的。
登录账号
登录账号允许一个用户访问SQL Server数据或者管理选项。登录账号允许用户仅仅是登录到SQL Server上并且显示那些可以让访客(guest)访问的数据库。(guest账号不是缺省设置的,必须创建)
SQL Server提供了两种类型的登录安全性。Windows NT验证模式(也称为集成的)和SQL Server验证模式(也称为标准的)。SQL Server 7.0还支持标准的和集成的安全性的联合使用,称为混合的。
Windows NT验证模式在检验登录连接时使用Windows NT内建的安全机制,并且依赖用户的Windows NT安全信任。用户不需要为SQL Server输入登录ID和口令--其登录信息直接从网络连接上截取。当发生连接时,一个条目就被写入syslogins表,并且在Windows NT和SQL Server之间加以验证。这种方式叫做可信连接,其工作原理同两台Windows NT服务器之间的可信关系是一样的。此功能同Oracle中用于用户账号的IDENTIFIED EXTERNALLY选项是类似的。
SQL Server验证模式在用户请求访问SQL Server时要求用户输入登录ID和口令。这种方式又叫做不信任连接。此功能同Oracle中用于用户账号的IDENTIFIED BY PASSWORD选项是类似的。使用标准安全模式,登录仅仅提供用户访问SQL Server数据库引擎的能力,不允许用户访问用户数据库。
欲了解关于安全机制的更多信息,请参看SQL Server联机手册。
组、角色和许可(Groups, roles, and permissions)
Microsoft SQL Server和Oracle都使用许可来加强数据库安全性。SQL Server用语句级的许可来限制创建新的数据库对象的能力。(同Oracle一样)
SQL Server还提供了对象级的许可。像Oracle一样,对象级所有权是分配给对象的创建者的,并且不能过户。在其他用户可以访问对象之前必须给予他们对象级的许可。sysadmin 固定服务器角色、db_owner 固定数据库角色、或者db_securityadmin 固定数据库角色的成员同样可以给予其他用户对某个用户对象的许可。
SQL Server语句级和对象级的许可可以直接赋予数据库用户账号。但是,通常更简单的方法是赋予数据库角色管理员许可。SQL Server角色用来赋予或者撤消数据库用户组的特权(同Oracle角色非常相象)。角色(Roles)是一个带有特殊数据库的数据库对象。每次安装都有一些固定的服务器角色,这些角色在数据库之上工作。一个固定服务器角色的例子是sysadmin。Windows NT组也可以作为SQL Server登录,就像数据库用户一样。许可可以赋予一个Windows NT组或者一个Windows NT用户。
一个数据库可以有任意数量的角色或者Windows NT组。缺省的public角色总是可以在任何一个数据库上找到,这些角色不能被清除。public角色的功能很像Oracle中的PUBLIC账号。每个数据库用户都是public角色的成员。在public角色之外,一个数据库用户还可以是任意数量角色的成员。Windows NT用户或组也可以是任意数量角色的成员,同样,他们也是public角色的成员。
数据库用户和Guest账号(Database users and the guest account)
在Microsoft SQL Server中,一个用户登录账号必须被授权使用一个数据库和它的对象。登录账号可以用下面方法中的一种来访问数据库:
登录账号可以被设定为数据库用户。
登录账号可以在数据库中使用访客(Guest)账号。
一个Windows NT组登录可以被映射为一个数据库角色。作为该组成员的单个Windows NT账号就可以连接到数据库上。
db_owner或者db_accessadmin角色或者sysadmin固定服务器角色的成员可以创建数据库用户账号角色。一个账号可以包含一些参数:SQL Server登录ID,数据库用户名(可选)、以及一个角色名(可选)。数据库用户名不一定要和用户登录ID一样。如果未提供一个数据库用户名,则用户的登录ID和数据库用户名就是一样的。如果未提供一个角色名,则该数据库用户就仅是public角色的成员。在创建了数据库用户之后,用户可以根据需要分配任意的角色。
db_owner或者db_accessadmin角色的成员也可以创建一个guest账号。guest账号允许任意有效的SQL Server登录账号访问一个数据库,甚至不需要有数据库用户账号。缺省情况下,guest账号继承了分配给public角色的特权;但是,这些特权可以修改为多于或者少于public账号的特权。
一个Windows NT用户或者一个组的账号可以被赋予访问数据库的权利,就像SQL Server登录所能做的一样。如果一个Windows NT组的一个成员连接数据库,该用户会收到分配给这个组的许可。如果该用户是不止一个Windows NT组的成员,则他会收到所有这些组对数据库的权限的集合。
Sysadmin角色(The sysadmin role)
Microsoft SQL Server sysadmin固定服务器角色中的成员拥有与Oracle DBA组中的成员相似的权限。在SQL Server 7.0中,如果SQL Server是安装在一台Windows NT计算机上,那么以sa SQL Server验证模式登录的账号缺省为该角色的成员,也就是本地Administrator组中的成员。一个sysadmin角色中的成员可以增加或者删除Windows NT用户和组,以及SQL Server登录账号。典型的该角色中的成员有以下职责:
安装SQL Server。
配置服务器和客户端。
创建数据库。*
设立登录权限和用户许可。*
将数据导入或者导出SQL Server数据库。*
备份和恢复数据库。*
执行和维护复制。
安排无人值守的操作。*
监视和调试SQL Server的性能。*
诊断系统问题。
*这些项目可以委派给其他安全性角色和用户。
在SQL Server 7.0中,对于sysadmin固定服务器角色中的成员能干什么是没有限制的。因此,该角色中的成员可以通过一个特殊的SQL Server实例访问任何数据库、所有的对象(包括数据)。像一个Oracle DBA一样,有一些命令和系统程序是只有sysadmin角色中的成员才能使用的。
db_owner角色
虽然Microsoft SQL Server数据库在使用上和Oracle表空间很相似,但是它们在管理上是不一样的。每个SQL Server数据库都是一个自持的管理域。每个数据库都标明了数据库所有者(dbo)。该用户总是db_owner固定数据库角色的成员。其他用户也可以是db_owner角色的成员。该角色中的所有成员都可以管理与他的数据库相关的管理任务。(不象在Oracle中,DBA管理所有数据库的管理任务)。这些管理任务包括:
管理数据库访问。
修改数据库设置(只读,单用户,等等)。
备份和恢复数据库目录。
授予和取消数据库许可。
创建和删除数据库对象。
db_owner角色中的成员可以在他们的数据库上做任何事情。分配给该角色的大多数权利被分给一些固定数据库角色,或者也可以赋予数据库用户。在数据库上行使db_owner特权并不需要赋予sysadmin服务器范围特权。
安装和配置Microsoft SQL Server
了解了Oracle和SQL Server之间基本结构上的差异以后,你就可以开始进行移植过程的第一步了。SQL Server Query Analyzer将用来运行下面的脚本:
- 使用Windows NT基于软件的RAID或者基于硬件的RAID第五级来创建一个足够放下你的所有数据的逻辑驱动器。对空间的估算可以通过计算被Oracle系统、临时文件以及应用程序表空间占用的文件空间大小来进行。
- 使用Windows NT基于软件的RAID或者基于硬件的RAID第一级创建一个第二逻辑驱动器来放事务日志。该驱动器的大小起码应该和在线恢复以及后滚表空间的总的大小一致。
- 使用SQL Server Enterprise Manager创建一个和Oracle应用程序表空间名字一样的数据库。(示例应用程序使用的数据库名字叫做USER_DB)标明文件位置,使它们分别和你在第一步以及第二步中为数据和事务创建的磁盘位置一致。如果你使用多个Oracle表空间,不需要也建议你不要创建多个SQL Server数据库,RAID会自动为你分配的。
- 创建SQL Server登录账号:
USE MASTER
EXEC SP_ADDLOGIN STUDENT_ADMIN, STUDENT_ADMIN
EXEC SP_ADDLOGIN DEPT_ADMIN, DEPT_ADMIN
EXEC SP_ADDLOGIN ENDUSER1, ENDUSER1
GO
|
- 为数据库添加角色:
USE USER_DB
EXEC SP_ADDROLE DATA_ADMIN
EXEC SP_ADDROLE USER_LOGON
GO
|
- 为角色授予许可:
GRANT CREATE TABLE, CREATE TRIGGER, CREATE VIEW,
CREATE PROCEDURE TO DATA_ADMIN
GO
|
- 增加作为数据库用户账号的登录账号:
EXEC SP_ADDUSER ENDUSER1, ENDUSER1, USER_LOGON
EXEC SP_ADDUSER DEPT_ADMIN, DEPT_ADMIN, DATA_ADMIN
EXEC SP_ADDUSER STUDENT_ADMIN, STUDENT_ADMIN, DATA_ADMIN
GO
|
定义数据库对象
Oracle数据库对象(表、视图和索引)可以很容易的移植到Microsoft SQL Server上,这是因为两个数据库都基本遵循SQL-92标准,该标准承认对象定义。把Oracle SQL的表、索引和视图的定义转换为SQL Server的表、索引和视图的定义只需要做相对简单的语法改变。下表指出了Oracle和Microsoft SQL Server之间的数据库对象的某些不同之处。
类别
|
Microsoft SQL Server
|
Oracle
|
列数
|
1024
|
254
|
行尺寸
|
8060 byte, 外加16 byte用来指向每一个text或者image列
|
无限制 (每行只允许有一个long或者long raw)
|
最大行数
|
无限制
|
无限制
|
BLOB类型存储
|
行中存储一个16-byte 指针。数据存储在其他数据页。
|
每表一个long或者long raw。 必须在行的结尾。数据存储在行的同一个块里。
|
分簇表索引
|
每表一个
|
每表一个(index-organized tables)
|
未分簇的表索引
|
每表249
|
无限制
|
在单一索引中的最大索引列数
|
16
|
16
|
索引中列值的最大长度
|
900 bytes
|
? block
|
表名约定
|
[[[server.]database.]owner.]
table_name
|
[schema.]table_name
|
视图名约定
|
[[[server.]database.]owner.]
table_name
|
[schema.]table_name
|
索引名约定
|
[[[server.]database.]owner.]
table_name
|
[schema.]table_name
|
假设你是从一个Oracle脚本或者程序开始的,该脚本或者程序用来创建你的数据库对象。拷贝你的脚本或者程序并且进行如下修改。这些修改将在本部分的其他地方加以讨论。该例子是从示例应用程序脚本Oratable.sql和Sstable.sql中截取的:
- 确保数据库对象标识遵循Microsoft SQL Server命名法则。你可能只需要修改索引的名字。
- 修改数据存储参数使之能在SQL Server下工作。如果你使用RAID,就不需要任何存储参数了。
- 修改Oracle约束定义使之能在SQL Server中工作。如果需要的话,创建一个触发器以支持外部键DELETE CASCADE语句。如果表跨数据库的话,使用触发器来增强外部键的关系。
- 修改CREATE INDEX语句以利用分簇的索引。
- 使用数据转换服务来创建新的CREATE TABLE语句。回顾该语句,注意Oracle数据类型是如何映射到SQL Server数据类型上的。
- 清除所有的CREATE SEQUENCE语句。在CREATE TABLE或者ALTER TABLE语句中使用同等列来替换顺序的使用。
- 如果需要的话,修改CREATE VIEW语句。
- 清除所有对同义字的引用。
- 评估对Microsoft SQL Server临时表的使用和其在你的应用程序中的用处。
- 把所有的Oracle的CREATE TABLE…AS SELECT命令改为SQL Server的SELECT…INTO语句。
- 评估潜在的对用户定义规则、数据类型和缺省的使用。
数据对象标识符
下表比较了Oracle和Microsoft SQL Server是如何处理对象标识符的。在许多情况下,当移植到SQL Server上时,你不需要改变对象的名字。
Oracle
|
Microsoft SQL
|
1-30 字符长度。
数据库名称:最多8个字符长度。
数据库连接名称:最多128个字符长度。
|
1-128 Unicode字符长度。
临时表名称:最多116个字符。
|
标识符的名称必须用:字母、包含文字数字的字符、或者字符_, $, 和 #开头
|
标识符名称可以用:字母数字字符、或者_开头,实际上可以用任何字符开头。
如果标识符用空格开头,或者包含了不是_、@、#、或者$的字符,你必须用[](定界符)包围标识符名称
如果一个对象用下面这些字符开头:
@ 则表明该对象是一个本地变量。
# 则该对象是一个本地临时对象。
## 则该对象是一个全局临时对象
|
表空间名必须唯一.
|
数据库名必须唯一
|
标识符名在用户账号(计划,Schema)范围内必须唯一。
|
标识符名在数据库用户账号范围内必须唯一
|
列名在表和视图范围内必须唯一。
|
列名在表和视图范围内必须唯一。
|
索引名在用户账号(Schema)范围内必须唯一。
|
索引名在数据库表名范围内必须唯一
|
修饰表名
当访问存在于你的用户账号中的表时,该表可以简单的通过未经限制的表名来选中。访问其他Oracle计划中的表就需要把该计划的名字作为前缀加到表名上,两者之间用点号(.)隔开。Oracle同义字可以提供更高的位置透明度。
涉及到表时,Microsoft SQL Server采用一种不同的方法。因为一个SQL Server登录账号可以在多个数据库中用同一个名字创建一个表,所以采用下面的方法来访问表和视图:[[数据库名字]所有者名字]表名]
用……访问一个表
|
Oracle
|
Microsoft SQL Server
|
你的用户账号
|
SELECT *
FROM STUDENT
|
SELECT * FROM USER_DB.STUDENT_
ADMIN.STUDENT
|
其他模式(schema)
|
SELECT * FROM STUDENT_ADMIN.STUDENT
|
SELECT * FROM OTHER_DB.STUDENT_
ADMIN.STUDENT
|
这是一些为Microsoft SQL Server表和视图命名的指导方针:
- 使用数据库名字和用户名字是可选的。如果一个表只通过名字加以引用(例如,STUDENT),SQL Server在当前数据库中以当前用户帐号搜索该表。如果没有找到,就在数据库中寻找由dbo的保留用户名拥有的具有同样名字的对象。表名在同一个数据库中的同一个用户帐号下必须是唯一的。
- 同一个SQL Server登录账号可以在多个数据库中拥有同样名字的表。例如,ENDUSER1账号拥有下列数据库对象:USER_DB.ENDUSER1.STUDENT和OTHER_DB.ENDUSER1.STUDENT。这里所加的限制是数据库用户名而不是SQL Server登录名,因为两者不一定要一样。
同时,这些数据库的其他用户可以有同样名字的对象:
- USER_DB.DBO.STUDENT
- USER_DB.DEPT_ADMIN.STUDENT
- USER_DB.STUDENT_ADMIN.STUDENT
- OTHER_DB.DBO.STUDENT
因此,建议你在引用数据库对象时包含所有者的名字。如果应用程序有多个数据库,建议你再把数据库名字也包含在引用中。如果查询跨越多个服务器,还要包括服务器名。
SQL Server的每个连接都有一个当前数据库上下文,这是在登录时用USE语句设置的。例如,假设有下面的场景:
- 一个用户,使用ENDUSER1账号,登录到USER_DB数据库上。用户请求STUDENT表。SQL Server就查询ENDUSER1.STUDENT表。如果找到,SQL Server就在USER_DB.ENDUSER1.STUDENT表上做要求的数据库操作。如果在ENDUSER1数据库账号下没有找到该表,SQL Server就为该数据库以dbo账号搜寻USER_DB.DBO.STUDENT。如果还是找不到该表,SQL Server就返回一个错误消息,指出该表不存在。
- 如果另一个用户,例如DEPT_ADMIN拥有该表,则该表必须以数据库用户名作为前缀(DEPT_ADMIN.STUDENT)。另外,数据库名字缺省为在当前上下文中的数据库名字。
- 如果被引用的表在另一个数据库中,则数据库名必须作为引用的一部分。例如,要访问在OTHERDB数据库中由ENDUSER1拥有的表STUDENT,就需要用OTHER_DB.ENDUSER1.STUDENT来引用。
可以在数据库和表名之间加两个点号来省略对象的所有者名。例如,如果应用程序引用STUDENT_DB..STUDENT,SQL Server就做如下搜寻:
- STUDENT_DB.current_user.STUDENT
- STUDENT_DB.DBO.STUDENT
如果应用程序一次只使用一个数据库,在做对象引用时省略数据库名字,这样的话,该应用程序可以方便的用于其他数据库。所有的对象引用都隐含的访问当前所用的数据库。这对于你要想在同一台服务器上维持一个测试数据库和一个产品数据库时很有用
创建表
因为Oracle和SQL Server都支持SQL-92条目级(entry-level)的关于标识RDBMS对象的协议,CREATE TABLE的语法是相似的。
Oracle
|
Microsoft SQL
|
CREATE TABLE
[schema.]table_name ( {col_name column_properties
[default_expression] [constraint [constraint
[...constraint]]]| [[,] constraint]} [[,] {next_col_name | next_constraint}...] )
[Oracle Specific Data Storage Parameters]
|
CREATE TABLE [server.][database.][owner.] table_name
(
{col_name column_properties[constraint
[constraint [...constraint]]]| [[,] constraint]}
[[,] {next_col_name | next_constraint}...]
)
[ON filegroup_name]
|
Oracle数据库对象名字是不分大小写的。在Microsoft SQL Server中,数据库对象的名字可以是大小写敏感的,这要看安装时的设置。
当SQL Server第一次设置的时候,缺省的排序顺序是字典顺序,区分大小写。(可以用SQL ServerSetup来做不同的设置)因为Oracle对象的名字总是唯一的,你在把数据库对象移植到SQL Server上时不会遇到任何的麻烦。建议你把Oracle和SQL Server中的所有的表和列的名字都写成大写的以避免万一有用户安装了区分大小写的SQL Server时出问题。
表和索引存储参数
对于Microsoft SQL Server,使用RAID通常可以简化数据库对象的放置。在表的结构中集成了一个SQL Server的分簇的索引,就像一个Oracle索引组织表一样。
Oracle
|
Microsoft SQL
|
CREATE TABLE DEPT_ADMIN.DEPT (
DEPTVARCHAR2(4) NOT NULL,
DNAMEVARCHAR2(30) NOT NULL,
CONSTRAINT DEPT_DEPT_PK
PRIMARY KEY (DEPT)
USING INDEX TABLESPACE USER_DATA
PCTFREE 0 STORAGE (INITIAL 10K NEXT 10K
MINEXTENTS 1 MAXEXTENTS UNLIMITED), CONSTRAINT DEPT_DNAME_UNIQUE
UNIQUE (DNAME)
USING INDEX TABLESPACE USER_DATA
PCTFREE 0 STORAGE (INITIAL 10K NEXT 10K
MINEXTENTS 1 MAXEXTENTS UNLIMITED) )
PCTFREE 10PCTUSED 40
TABLESPACE USER_DATA
STORAGE (INITIAL 10K NEXT 10K
MINEXTENTS 1 MAXEXTENTS UNLIMITED
FREELISTS 1)
|
CREATE TABLE USER_DB.DEPT_ADMIN.DEPT (
DEPTVARCHAR(4) NOT NULL,
DNAMEVARCHAR(30) NOT NULL,
CONSTRAINT DEPT_DEPT_PK
PRIMARY KEY CLUSTERED (DEPT),
CONSTRAINT DEPT_DNAME_UNIQUE
UNIQUE NONCLUSTERED (DNAME)
)
|
用SELECT语句创建表
使用Oracle,一个表可以用任何有效的SELECT命令创建。Microsoft SQL Server提供了同样的功能,但是语法不一样。
Oracle
|
Microsoft SQL
|
CREATE TABLE STUDENTBACKUP AS SELECT * FROM STUDENT
|
SELECT * INTO STUDENTBACKUP
FROM STUDENT
|
要SELECT…INTO能够起作用,必须将使用该程序的数据库的选项select into/bulkcopy设定为true。(数据库所有者可以用SQL Server Enterprise Manager或者Transact-SQL的sp_dboption系统存储程序来设置该选项)。用sp_helpdb系统存储过程来检查数据库的状态。如果select into/bulkcopy未设定为true,你仍然可以用SELECT语句拷贝到临时表中,就像下面这样:
SELECT * INTO #student_backup FROM user_db.student_admin.student
当用SELECT.. INTO语句来创建新的表时,其参考的完整性定义不会转换到新的表中。
将select into/bulkcopy设定为true的要求可能会使移植的过程变得复杂。如果你必须用SELECT语句拷贝数据到表中,请首先创建表,然后再用INSERT INTO…SELECT语句来载入该表。对于Oracle和SQL Server来说,语法是一样的,也不需要设置任何数据库选项。
视图
在Microsoft SQL Server中创建视图的语法同Oracle一样。
Oracle
|
Microsoft SQL
|
CREATE [OR REPLACE] [FORCE |
NOFORCE] VIEW [schema.]view_name
[(column_name [, column_name]...)]
AS select_statement
[WITH CHECK OPTION [CONSTRAINT
name]]
[WITH READ ONLY]
|
CREATE VIEW [owner.]view_name
[(column_name [, column_name]...)]
[WITH ENCRYPTION]
AS select_statement [WITH CHECK OPTION]
|
SQL Server视图要求表必须存在,并且视图的所有者必须有访问在SELECT语句中标明的数据库的权限(同Oracle中的FORCE选项相似)。
缺省情况下,不会检查视图上的数据修改语句来判定受影响的行是否在视图的范围内。要检查所有的修改,请使用WITH CHECK OPTION。对于WITH CHECK OPTION主要的不同之处在于,Oracle将其作为约束来定义,而SQL Server不是。此外,两者的功能是一样的。
在定义视图的时候,Oracle提供了一个WITH READ ONLY选项。SQL Server应用程序可以用仅向视图用户提供SELECT权限的方法来达到同样的结果。
SQL Server和Oracle视图都支持派生列、使用数学表达式、函数以及常量表达式。SQL Server的某些特殊的不同之处是:
- 如果数据修改只影响一个基本表,则数据修改语句(INSERT或者UPDATE)可以存在于多个视图上。单个语句中的数据修改语句不能用在超过一个表上。
- READTEXT或者WRITETEXT不能用于视图中的列。
- 不能使用ORDER BY、COMPUTE、FOR BROWSE、或者COMPUTE BY子句。
- 在视图中不能使用INTO关键字。
当一个视图是和一个外部连接一起定义的,并且查询限定在外部接合点的内部表上时,SQL Server和Oracle的结果会有所不同。在大多数情况下,Oracle视图很容易转化为SQL Server视图。
Oracle
|
Microsoft SQL
|
CREATE VIEW STUDENT_ADMIN.STUDENT_GPA
(SSN, GPA)
AS SELECT SSN, ROUND(AVG(DECODE(grade
,'A', 4
,'A+', 4.3
,'A-', 3.7
,'B', 3
,'B+', 3.3
,'B-', 2.7
,'C', 2
,'C+', 2.3
,'C-', 1.7
,'D', 1
,'D+', 1.3
,'D-', 0.7
,0)),2)
FROM STUDENT_ADMIN.GRADE
GROUP BY SSN
|
CREATE VIEW STUDENT_ADMIN.STUDENT_GPA
(SSN, GPA)
AS SELECT SSN, ROUND(AVG(CASE grade
WHEN 'A' THEN 4
WHEN 'A+' THEN 4.3
WHEN 'A-' THEN 3.7
WHEN 'B' THEN 3
WHEN 'B+' THEN 3.3
WHEN 'B-' THEN 2.7
WHEN 'C' THEN 2
WHEN 'C+' THEN 2.3
WHEN 'C-' THEN 1.7
WHEN 'D' THEN 1
WHEN 'D+' THEN 1.3
WHEN 'D-' THEN 0.7
ELSE 0
END),2)
FROM STUDENT_ADMIN.GRADE
GROUP BY SSN
|
索引
Microsoft SQL Server提供了分簇和未分簇的索引结构。这些索引是由来自于一个叫做B-tree的树型结构中的页构成的(同Oracle中的B-tree索引结构相似)。起始页(“根”级)说明了表中值的范围。“根”级页中的每一个范围指向其他页(判断节点),该节点包含了表中值的更小的范围。以此类推,该节点又可以指向其他的判断节点,这样就缩小了搜索的范围。树型结构的最后一级叫做“叶”级。
分簇的索引
分簇的索引在Oracle中是以索引组织表的形式实现的。一个分簇的索引是一个物理的包含在一个表中的索引。表和索引分享同一块存储空间。分簇的索引按索引顺序物理的重排数据行,建立起中间判断节点。索引的“叶”页包含了真实的表数据。这个结构允许每个表只有一个分簇的索引。Microsoft SQL Server为表自动的创建一个分簇的索引,无论该表设置了PRIMARY KEY还是UNIQUE约束。分簇的索引对下面这些是有用的:
- 主键(Primary keys)
- 不能被更新的列。
- 返回一个值的范围的查询,使用诸如BETWEEN、>、>=、<、以及<=这样的操作符,例如:
SELECT * FROM STUDENT WHERE GRAD_DATE
BETWEEN '1/1/97' AND '12/31/97'
SELECT * FROM STUDENT WHERE LNAME = 'SMITH'
- 被用做排序操作的列(ORDER BY、GROUP BY)
例如,在STUDENT表上,在ssn的主键上包含一个未分簇的索引是很有用的,而分簇的索引可以在lname、fname(last name、first name)上创建,因为这是一种常用的区分学生的方法。
- 分布表上的更新行为可以防止出现“热点”。热点通常是由于多个用户向一个有上升键的表中填充而引起的。这样的情景经常导致行级别的锁定。
删除和重建一个分簇的索引在SQL Server中是一种很普通的重新组织表的技术。这是一种确保数据页在磁盘上是连续的以及重建表中的一些可用空间的简单的方法。这同Oracle中导出、删除以及导入一个表是很相似的。
一个SQL Server分簇的索引与Oracle的簇在根本上是不一样的。一个Oracle的簇。一个Oracle的簇是两个或者更多的表的物理集合,它们分享同一个数据块,使用一个公共的列来作为簇键。SQL Server没有与Oracle簇相似的结构。
作为一个普遍的原则,在表上定义一个分簇的索引将提高SQL Server的性能并且加强空间管理。如果你不知道对于给定表的查询和更新模式,你可以在主键上创建一个分簇的索引。
下表摘录自示例应用程序的源代码。请注意SQL Server“簇”化索引的使用。
Oracle
|
Microsoft SQL
|
CREATE TABLE STUDENT_ADMIN.GRADE (
SSNCHAR(9) NOT NULL,
CCODEVARCHAR2(4) NOT NULL,
GRADEVARCHAR2(2) NULL,
CONSTRAINT GRADE_SSN_CCODE_PK
PRIMARY KEY (SSN, CCODE)
CONSTRAINT GRADE_SSN_FK
FOREIGN KEY (SSN) REFERENCES
STUDENT_ADMIN.STUDENT (SSN),
CONSTRAINT GRADE_CCODE_FK
FOREIGN KEY (CCODE) REFERENCES
DEPT_ADMIN.CLASS (CCODE)
)
|
CREATE TABLE STUDENT_ADMIN.GRADE (
SSNCHAR(9) NOT NULL,
CCODEVARCHAR(4) NOT NULL,
GRADEVARCHAR(2) NULL,
CONSTRAINT
GRADE_SSN_CCODE_PK
PRIMARY KEY CLUSTERED (SSN, CCODE),
CONSTRAINT GRADE_SSN_FK
FOREIGN KEY (SSN) REFERENCES
STUDENT_ADMIN.STUDENT (SSN),
CONSTRAINT GRADE_CCODE_FK
FOREIGN KEY (CCODE) REFERENCES
DEPT_ADMIN.CLASS (CCODE)
)
|
未分簇的索引
在未分簇的索引中,索引数据和表数据在物理上是分开的,并且表中的行并不是按顺序存储在索引中的。你可以把Oracle索引定义移植到Microsoft SQL Server未分簇的索引定义上(就像在下表中显示的一样)。可是,考虑到性能的缘故,你可能希望选择表的其中一个索引把它创建为分簇的索引。
Oracle
|
Microsoft SQL
|
CREATE INDEX
STUDENT_ADMIN.STUDENT_
MAJOR_IDX
ON STUDENT_ADMIN.STUDENT (MAJOR)
TABLESPACE USER_DATA
PCTFREE 0
STORAGE (INITIAL 10K NEXT 10K
MINEXTENTS 1 MAXEXTENTS
UNLIMITED)
|
CREATE NONCLUSTERED INDEX
STUDENT_MAJOR_IDX
ON USER_DB.STUDENT_
ADMIN.STUDENT (MAJOR)
|
索引语法和命名
在Oracle中,一个索引的名字在一个用户账号中是唯一的。在In Microsoft SQL Server,一个索引的名字在一个表名中必须是唯一的,但是不必在用户名和数据库名中唯一。因此,在SQL Server中创建或者删除索引时,你必须说明表名和索引名。另外,SQL Server的DROP INDEX语句可以一次删除多个索引。
Oracle
|
Microsoft SQL
|
CREATE [UNIQUE] INDEX [schema].index_name
ON [schema.]table_name (column_name [, column_name]...)
[INITRANS n]
[MAXTRANS n]
[TABLESPACE tablespace_name]
[STORAGE storage_parameters]
[PCTFREE n]
[NOSORT]
DROP INDEX ABC;
|
CREATE [UNIQUE] [CLUSTERED | NONCLUSTERED]
INDEX index_name ON table (column [,…n])
[WITH
[PAD_INDEX]
[[,] FILLFACTOR = fillfactor]
[[,] IGNORE_DUP_KEY]
[[,] DROP_EXISTING]
[[,] STATISTICS_NORECOMPUTE]
]
[ON filegroup]
DROP INDEX USER_DB.STUDENT.DEMO_IDX, USER_DB.GRADE.DEMO_IDX
|
索引数据存储参数
Microsoft SQL Server功能选项中的FILLFACTOR选项在很多方面与Oracle中的PCTFREE变量相似。当表的尺寸增加的时候,索引页也相应改变以容纳新的数据。索引必须自己进行重新组合以容纳新的数据。只有在创建索引的时候,才使用填充参数百分比,而且在这之后也不加以维护。
FILLFACTOR选项(0~100)控制着在创建索引时应该留下多少空间。如果没有表明参数,就使用缺省参数,该参数是0,表示将完全填充索引的“叶”页,并且在每个判断节点为至少一个条目留下空间(如果有两个条目,则表示是一个不唯一的“簇”化索引)。
一个较低的填充因数将会减少索引页的分裂,但是会增加B-tree结构的层数。较高的填充因数能更有效的使用索引页空间,只需要较少的磁盘I/O来访问索引数据,并且将会减少B-tree结构的层数。
PAD_INDEX选项表示,填充因数也将应用到判断节点页上,就象要用在索引的数据页上一样。
虽然在 Oracle中可能需要调整PCTFREE参数以优化性能。但是在CREATE INDEX语句中很少使用FILLFACTOR参数。填充因数是为性能优化而提供的。但是它仅仅在一个表上为已有数据创建索引时才有用,并且只有在你能精确的预测数据在未来的变化时才有用。
如果你将Oracle中的PCTFREE参数设为0,可以考虑将它设为100。这在表中不会发生数据输入和修改(只读表)时是很有用的。如果填充因数设为100,服务器将创建这样一个索引,它的每一页都是完全填满的。
忽略重复的关键字
无论在Oracle还是在Microsoft SQL Server中,用户都不能在一个或者一些唯一索引的列中输入重复的值。这样做将会产生一个错误消息。然而,SQL Server允许开发人员选择INSERT或者UPDATE语句将如何处理这个错误。
如果在CREATE INDEX语句中使用了IGNORE_DUP_KEY,并且执行了一个创建重复的关键字的INSERT或者UPDATE语句,SQL Server将给出一个警告信息,并且忽略重复行。如果没有使用IGNORE_DUP_KEY,SQL Server将给出一个错误信息,并且后滚整个INSERT语句。如果需要了解关于这个选项的更多信息,请参看SQL Server联机手册。
使用临时表
一个Oracle应用程序也许必须创建一个暂时存在的表。应用程序必须确保在某个时候删除所有为此目的创建的表。如果应用程序不这样做,那么表空间将很快变得混乱,难以管理。
Microsoft SQL Server提供了临时表数据库对象,这个表就是为上面提到的目的创建的。这样的表总是在tempdb数据库中创建的。表的名字决定了该表在tempdb数据库中要存在多长时间。
表名
|
描述
|
#table_name
|
这个本地临时表只在用户会话或者创建它的过程的生命期内存在。在用户退出登录或者创建它的过程完成以后,该表自动删除。该表不能在多个用户之间共享。其它数据库用户不能访问该表。在该表上不能赋予或者撤消许可。
|
##table_name
|
该表也典型的存在于用户会话或者创建它的过程的生命期内。但该表可以被多个用户共享。在最后一个引用它的用户会话断开以后,该表自动删除。所有其它数据库的用户都可以访问该表。在该表上不能赋予或者撤消许可。
|
可以为临时表定义索引。但是只能在那些在tempdb中显明的创建的表上创建视图,这些表的名字前不加#或者##前缀。下面的例子显示了一个临时表和相应的索引的创建。当用户退出的时候,表和索引就自动删除了。
SELECT SUM(ISNULL(TUITION_PAID,0)) SUM_PAID, MAJOR INTO #SUM_STUDENT
FROM USER_DB.STUDENT_ADMIN.STUDENT GROUP BY MAJOR
CREATE UNIQUE INDEX SUM STUDENT IDX ON #SUM STUDENT (MAJOR)
|
在你的程序代码中使用临时表,你可以发现它的好处。
数据类型
同Oracle比起来,Microsoft SQL Server在数据库类型的选择上更强大。在Oracle和SQL Server数据类型之间有很多可能的转换方式。我们建议你使用DTS向导来自动创建新的CREATE TABLE语句。需要的时候,你还可以修改它。
Oracle
|
Microsoft SQL
|
CHAR
|
推荐使用char。 char 类型的列比varchar列的访问速度要稍微快一点,因为char列使用一个固定的存储长度。
|
VARCHAR2
和 LONG
|
varchar 或者 text. (如果在你的Oracle列中数据值的长度小于或等于8000 bytes ,使用varchar;否则,你必须使用text。)
|
RAW 和
LONG RAW
|
varbinary 或者 image. (如果在你的Oracle列中数据值的长度小于或等于8000 bytes,使用varbinary;否则,你必须使用image。)
|
NUMBER
|
如果整数在1到255之间, 使用tinyint.
如果整数在-32768到32767之间,使用smallint.
如果整数在-2,147,483,648到2,147,483,647之间,使用int.
如果你需要浮点型的数,使用numeric (精确且可以定标).
注意: 不要使用float或者real, 因为可能会发生截断(Oracle NUMBER和 SQL Server numeric 不会截断).
如果你不确定,使用numeric; 它同Oracle NUMBER数据类型非常相似。
|
DATE
|
datetime.
|
ROWID
|
使用identity列类型
|
CURRVAL, NEXTVAL
|
使用identity列类型, 以及@@IDENTITY, IDENT_SEED(), 和IDENT_INCR() 函数。
|
SYSDATE
|
GETDATE().
|
USER
|
USER.
|
使用Unicode数据
Unicode规范定义了一个编码方案,该方案使用单一编码方式为全世界范围内业务上使用的所有字符编码。所有的计算机都能使用单一的Unicode编码把Unicode数据中的位模式转换成为字符。这个方案确保了在所有的计算机上,同样的位模式转换为同样的字符。数据可以自由的从一个数据库或者一台计算机传送到另一个上面,而不用考虑接受系统能否把位模式正确的转换成字符。
使用一个字节来表示字符的方法有一个问题,就是这种数据类型只能表示256个字符。这样就为不同的语言产生了多个编码规范(或者叫做代码页)。这样做也不可能处理日文或者韩文这样有上千个字符的语言。
Microsoft SQL Server把在SQL Server中安装了代码页的字符的位模式转换成char,varchar,或者text类型的列。客户端则使用操作系统安装的代码页来解释字符的位模式。现在有很多不同的代码页。有些字符只在某些代码页上才有,在别的代码页上就没有。某些字符在某些代码页上定义为一种位模式,在另外一些代码页上又定义为另一种位模式。如果你要建立一个必须处理各种语言的国际系统时,为那些满足语言要求或者多个国家的计算机挑选代码页就变得非常困难。同样,在和一个使用不同代码页的系统连接时,确保每一台计算机都能正确的实现字符转换也非常困难。
Unicode规范使用双字节编码方案解决了这个问题。使用双字节编码,就有足够的空间来覆盖最广泛使用的商业语言了。因为所有的Unicode系统都采用同样的位模式来代表所有的字符,在从一个系统转移到另一个系统的时候,就不会发生字符转换不正确的问题了。
在SQL Server中,nchat,nvarchar和ntext数据类型支持Unicode数据。如果需要了解关于SQL Server数据类型的更多信息,请参看SQL Server联机手册。
用户定义数据类型
可以为model数据库或者单用户数据库创建用户定义数据类型。如果是为model定义用户定义数据类型,则该数据类型可以被定义之后所有新创建的用户数据库使用。用户定义数据类型是通过sp_addtype系统存储程序来定义的。如果需要了解更多信息,请参看SQL Server联机手册。
你可以在CREATE TABLE和ALTER TABLE语句中使用用户定义数据类型,并且为它绑定缺省方式和规则。如果在表的创建过程使用用户定义数据类型时显明的定义了nullability,则它比在数据定义时定义的nullability优先级高。
下例显示了如何创建用户定义数据类型。参数是用户类型名字,数据类型和nullability。
sp_addtype gender_type, 'varchar(1)', 'not null'
go
|
这个能力对于解决与Oracle表创建脚本移植到SQL Server上相关的问题是很有用的。例如,要增加一个Oracle的DATE数据类型是非常简单的。
sp_addtype date, datetime
|
这个功能不能用在那些需要变长度的数据类型上,例如Oracle数据类型NUMBER。如果这样做,系统将会返回一个错误信息,告诉你需要标明数据长度。
sp_addtype varchar2, varchar
Go
Msg 15091, Level 16, State 1
You must specify a length with this physical type.
|
Microsoft timestamp列
timestamp列使得BROWSE模式修改和游标修改操作更有效。timestamp是这样一个数据类型,含有timestamp列的行有输入或者修改操作时,该数据类型自动修改。
timestamp列中的值不是按照实际的日期和时间存储的,而是作为binary(8)或者varbinary(8)存储的,这个值表示表中一行发生的事件的频率。一个表只能有一个timestamp列。
如果要了解更多信息,请参看SQL Server联机手册。
对象级许可
Microsoft SQL Server对象特权可以向任何其他数据库用户、数据库组以及public角色授予、拒绝授予、和撤消。SQL Server不允许对象的所有者授予其他用户、组或者public角色ALTER TABLE和CREATE INDEX特权,这一点与Oracle不同。这些特权必须被对象所有者保留。
GRANT语句创建一个安全系统的入口许可,该许可允许当前数据库中的一个用户可以操作当前数据库中的数据,或者执行特定的Transact-SQL语句。GRANT语句的语法在Oracle和SQL Server中是一样的。
DENY语句在安全系统中创建一个条目,拒绝当前数据库中的一个安全账号的许可,并且禁止该安全账号继承自该账号所属的组或者角色成员的许可。Oracle中没有DENY语句。REVOKE语句清除以前授予给当前数据库中一个用户的许可或者拒绝其许可。
Oracle
|
Microsoft SQL
|
GRANT {ALL [PRIVILEGES][column_list] | permission_list [column_list]}
ON {table_name [(column_list)]
| view_name [(column_list)]
| stored_procedure_name}
TO {PUBLIC | name_list }
[WITH GRANT OPTION]
|
GRANT
{ALL [PRIVILEGES] | permission[,…n]}
{
[(column[,…n])] ON {table | view}
| ON {table | view}[(column[,…n])]
| ON {stored_procedure | extended_procedure}
}
TO security_account[,…n]
[WITH GRANT OPTION]
[AS {group | role}]
REVOKE [GRANT OPTION FOR]
{ALL [PRIVILEGES] | permission[,…n]}
{
[(column[,…n])] ON {table | view}
| ON {table | view}[(column[,…n])]
| {stored_procedure | extended_procedure}
}
{TO | FROM}
security_account[,…n]
[CASCADE]
[AS {group | role}]
DENY
{ALL [PRIVILEGES] | permission[,…n]}
{
[(column[,…n])] ON {table | view}
| ON {table | view}[(column[,…n])]
| ON {stored_procedure | extended_procedure}
}
TO security_account[,…n]
[CASCADE]
|
如果需要了解关于对象级许可的更多信息,请参看 SQL Server联机手册。
在Oracle中,REFERENCES特权只能授予用户。SQL Server则允许把该特权授予数据库用户和数据库组。INSERT、UPDATE、DELETE和SELECT特权的授予在Oracle和SQL Server中以同样的方式处理。
加强数据完整性和商业规则
加强数据完整性确保数据库中数据的质量。规划表时重要的两个步骤是鉴定列中值的有效性和如何加强列中数据的完整性。数据完整性可以分为四类,它们是以不同的方式进行加强的。
完整性类型
|
如何强制
|
Entity integrity
|
PRIMARY KEY constraint
UNIQUE constraint
IDENTITY property
|
Domain integrity
|
Domain DEFAULT definition
FOREIGN KEY constraint
CHECK constraint
Nullability
|
Referential integrity
|
Domain DEFAULT definition
FOREIGN KEY constraint
CHECK constraint
Nullability
|
User-defined integrity
|
All column- and table-level constraints in CREATE TABLE
Stored procedures
Triggers
|
实体完整性(Entity Integrity)
实体完整性把特定表中的一行作为一个唯一的实体加以定义。实体完整性通过索引、UNIQUE约束、PRIMARY KEY约束或者IDENTITY特性加强表中标识列或者主关键字的完整性,
为约束命名
你总是可以显式的命名你的约束。如果你不这样做,Oracle和Microsoft SQL Server将使用不同的命名惯例来隐式的为约束命名。在命名上的不同会为你的移植带来不必要的麻烦。在删除约束或者使约束失效时将会出现问题,因为约束必须通过名字来删除。显式命名约束的语法在Oracle和SQL Server中是一样的。
CONSTRAINT constraint_name
|
主键和唯一列
SQL-92标准要求主关键字中的所有值都是唯一的并且该列不允许空值。Oracle和Microsoft SQL Server都是通过自动创建唯一的索引这种方式来强制实现唯一性的,无论是否定义了PRIMARY KEY或者UNIQUE约束。
虽然可以创建一个未分簇的索引,但是SQL Server缺省的为主关键字创建一个分簇的索引。Oracle在主关键字上的索引可以通过删除约束或者使约束失效的方法来清除,而SQL Server的索引只能通过删除约束来实现。
无论在哪种RDBMS中,其他关键字都可以定义一个UNIQUE约束。可以在任何表中定义多个UNIQUE约束。UNIQUE约束列可以为空。在SQL Server中,除非另外说明,否则将缺省的创建一个未分簇的索引
在移植你的应用程序时,重要的是注意到SQL Server只允许完全唯一的关键字(单个或者多个列索引)中有一行是NULL值的,而Oracle则允许完全唯一的关键字中任意行是NULL值。
Oracle
|
Microsoft SQL
|
CREATE TABLE DEPT_ADMIN.DEPT
(DEPT VARCHAR2(4) NOT NULL,
DNAME VARCHAR2(30) NOT NULL,
CONSTRAINT DEPT_DEPT_PK
PRIMARY KEY (DEPT)
USING INDEX TABLESPACE
USER_DATA
PCTFREE 0 STORAGE (
INITIAL 10K NEXT 10K
MINEXTENTS 1 MAXEXTENTS UNLIMITED), CONSTRAINT DEPT_DNAME_UNIQUE
UNIQUE (DNAME)
USING INDEX TABLESPACE USER_DATA
PCTFREE 0 STORAGE (
INITIAL 10K NEXT 10K
MINEXTENTS 1 MAXEXTENTS
UNLIMITED) )
|
CREATE TABLE USER_DB.DEPT_ADMIN.DEPT
(DEPTVARCHAR(4) NOT NULL,
DNAMEVARCHAR(30) NOT NULL,
CONSTRAINT DEPT_DEPT_PK
PRIMARY KEY CLUSTERED (DEPT),
CONSTRAINT DEPT_DNAME_UNIQUE
UNIQUE NONCLUSTERED (DNAME)
)
|
增加和清除约束
使约束失效可以改善数据库性能,并且使数据复制过程更加流畅。例如,当你在一个远程站点上重建或者复制表中的数据时,你不用重复约束检查,因为数据的完整性是在它原来输入数据库时就检查过的。你可以编制Oracle应用程序来使能或者失效约束(除了PRIMARY KEY和UNIQUE)。你可以在Microsoft SQL Server的ALTER TABLE语句中使用CHECK和WITH NOCHECK来达到同样的目的。
下面的插图显示了该过程的比较。
在SQL Server中,你在NOCHECK子句上使用ALL关键字来推迟所有的表的约束。
如果你的Oracle应用程序使用CASCADE选项来失效或者删除PRIMARY KEY或者UNIQUE约束,你也许需要重写某些代码,因为CASCADE选项同时失效或者删除父类和子类的完整性约束。
这是关于语法的示例:
DROP CONSTRAINT DEPT_DEPT_PK CASCADE
|
SQL Server应用程序必须修改成首先删除子类的约束,然后删除父类的约束。例如,为了删除DEPT表上的PRIMARY KEY约束,STUDENT.MAJOR和CLASS.DEPT相关列的外部关键字必须被删除。这是语法的示例:
ALTER TABLE STUDENT
DROP CONSTRAINT STUDENT_MAJOR_FK
ALTER TABLE CLASS
DROP CONSTRAINT CLASS_DEPT_FK
ALTER TABLE DEPT
DROP CONSTRAINT DEPT_DEPT_PK
|
ALTER TABLE增加和删除约束的语法在Oracle和SQL Server中的语法是一样的。
生成连续的数字值
如果你的Oracle应用程序使用SEQUENCEs,该选项可以很容易的改变以利用Microsoft SQL Server的IDENTITY特性。
类别
|
Microsoft SQL Server
|
语法
|
CREATE TABLE new_employees ( Empid int IDENTITY (1,1), Employee_Name varchar(60),
CONSTRAINT Emp_PK PRIMARY KEY (Empid)
)
If increment interval is 5:
CREATE TABLE new_employees ( Empid int IDENTITY (1,5), Employee_Name varchar(60),
CONSTRAINT Emp_PK PRIMARY KEY (Empid)
)
|
每个表拥有的标识列
|
一个
|
允许空值
|
否
|
使用缺省约束、值
|
不能使用.
|
强制唯一
|
是
|
在INSERT, SELECT INTO 或者bulk copy 语句完成以后,查询最大的当前标识数
|
@@IDENTITY (function)
|
返回创建标识列时指定的种子值
|
IDENT_SEED('table_name')
|
返回创建标识列时指定的增加值
|
IDENT_INCR('table_name')
|
SELECT语法
|
当在SELECT, INSERT, UPDATE, 和DELETE语句中引用带有IDENTITY属性的列时,可以在列名上使用IDENTOTY关键字
|
虽然IDENTITY特性使一个表中的行记数自动化,但是不同的表,如果每一个都有自己的标识列,可以产生同样的值。这是因为IDENTITY特性只能在使用它的表上被担保为唯一的。如果一个应用程序必须生成一个在整个数据库,或者全世界每一台联网计算机上的每一个数据库中唯一的标识列,可以使用ROWGUIDCOL特性,uniqueidentifier数据类型,以及NEWID函数。SQL Server使用全局独立的标识列来并入复制,确保该行在所有该表的拷贝中是唯一的标识。
如果需要了解关于创建和修改标识列的更多信息,请参看SQL Server联机手册。
域完整性
域完整性约束对给定列的有效入口。域完整性是通过限制类型(通过数据类型),格式(通过CHECK约束),或者可能值的范围(通过REFERENCE和CHECK约束)来实现的。
DEFAULT和CHECK约束
Oracle把缺省(default)当作一个列属性来对待,而Microsoft SQL Server把缺省当作一个约束来对待。SQL Server的DEFAULT约束可以包含整型值,内建的不带参数的函数(niladic函数),或者NULL。
要很方便的移植Oracle的DEFAULT列属性,你应该在SQL Server中定义列级别的不使用约束名字的DEFAULT约束。SQL Server为每一个DEFAULT约束生成一个唯一的名字。
用来定义CHECK约束的语法在Oracle和SQL Server中是一样的。搜索条件应该用布尔表达式来表示而且不能包含子查询。列级别的约束只能用在被约束列上,表级别的约束只能用在被约束的表中的列上。可以为一个表定义多个CHECK约束。SQL Server语法允许在一个CREATE TABLE语句中只创建一个列级别的CHECK约束,并且该约束可以有多个条件。
测试你修改过的CREATE TABLE语句的最好方式是使用SQL Server中的SQL Server Query Analyzer,并且只分析语法。输出结果将会指出任何错误。如果需要了解关于约束语法的更多信息,请参看SQL Server联机手册。
Oracle
|
Microsoft SQL
|
CREATE TABLE STUDENT_ADMIN.STUDENT (
SSN CHAR(9) NOT NULL,
FNAME VARCHAR2(12) NULL,
LNAME VARCHAR2(20) NOT NULL,
GENDER CHAR(1) NOT NULL
CONSTRAINT
STUDENT_GENDER_CK
CHECK (GENDER IN ('M','F')),
MAJOR VARCHAR2(4)
DEFAULT 'Undc' NOT NULL,
BIRTH_DATE DATE NULL,
TUITION_PAID NUMBER(12,2) NULL,
TUITION_TOTAL NUMBER(12,2) NULL,
START_DATE DATE NULL,
GRAD_DATE DATE NULL,
LOAN_AMOUNT NUMBER(12,2) NULL,
DEGREE_PROGRAM CHAR(1)
DEFAULT 'U' NOT NULL
CONSTRAINT
STUDENT_DEGREE_CK CHECK
(DEGREE_PROGRAM IN ('U', 'M', 'P', 'D')),
...
|
CREATE TABLE USER_DB.STUDENT
_ADMIN.STUDENT (
SSN CHAR(9) NOT NULL,
FNAME VARCHAR(12) NULL,
LNAME VARCHAR(20) NOT NULL,
GENDER CHAR(1) NOT NULL
CONSTRAINT STUDENT_GENDER_CK
CHECK (GENDER IN ('M','F')),
MAJOR VARCHAR(4)
DEFAULT 'Undc' NOT NULL,
BIRTH_DATE DATETIME NULL,
TUITION_PAID NUMERIC(12,2) NULL,
TUITION_TOTAL NUMERIC(12,2) NULL,
START_DATE DATETIME NULL,
GRAD_DATE DATETIME NULL,
LOAN_AMOUNT NUMERIC(12,2) NULL,
DEGREE_PROGRAM CHAR(1)
DEFAULT 'U' NOT NULL
CONSTRAINT STUDENT_DEGREE_CK
CHECK
(DEGREE_PROGRAM IN ('U', 'M',
'P','D')),
...
|
关于用户定义规则和缺省(default)要注意:关于Microsoft SQL Server规则和缺省的语法是考虑了向后兼容的,但是建议把CHECK约束和DEFAULT约束用在新的开发中。如果需要了解更多的信息,请参看SQL Server联机手册。
Nullability
Microsoft SQL Server和Oracle创建列约束来强制nullability。在Oracle的CREATE TABLE和ALTER TABLE语句中,列缺省是NULL,而不是NOT NULL。在Microsoft SQL Server,数据库和会话的设置可以越过在列定义中使用的数据类型的nullability。
你的所有的SQL脚本(无论是Oracle还是SQL Server),都必须显明的给出每一列的NULL和NOT NULL定义。要了解这个策略是如何实现的,请参看Oracle.sql和Sstable.sql这两个示例的表创建脚本。如果没有显明的定义,则列的nullability遵循如下的规则。
Null settings
|
Description
|
列是用一个用户定义数据类型定义的
|
SQL Server 使用在创建数据类型时指定的空值性。使用sp_help 系统存储过程来获取数据类型的缺省的空值性
|
列是用一个系统提供的数据类型定义的
|
如果系统提供的数据类型只有一个选项,则优先使用该选项。当前, bit数据类型只能被定义为NOT NULL。
如果任何会话设置为ON (用SET打开), 则:
如果ANSI_NULL_DFLT_ON是ON, 则指定为NULL.
如果ANSI_NULL_DFLT_OFF是ON, 则指定为NOT NULL.
如果任何数据库设置被修改过(用sp_dboption 系统存储过程修改), 则:
如果ANSI null default是true, 则指定为NULL.
如果ANSI null default是false, 则指定为NOT NULL
|
NULL/NOT NULL
没有定义
|
当没有显明的定义时(ANSI_NULL_DFLT选项一个都没有设定),会话将被修改,并且数据库被设定为缺省(ANSI null default是false),然后SQL Server指定它为NOT NULL。
|
引用完整性
下表提供了一个用来定义referential完整性约束的语法比较。
约束
|
Oracle
|
Microsoft SQL Server
|
PRIMARY KEY
|
[CONSTRAINT constraint_name]
PRIMARY KEY (col_name [, col_name2 [..., col_name16]])
[USING INDEX storage_parameters]
|
[CONSTRAINT constraint_name]
PRIMARY KEY [CLUSTERED | NONCLUSTERED] (col_name [, col_name2 [..., col_name16]])
[ON segment_name]
[NOT FOR REPLICATION]
|
UNIQUE
|
[CONSTRAINT constraint_name]
UNIQUE (col_name [, col_name2 [..., col_name16]])
[USING INDEX storage_parameters]
|
[CONSTRAINT constraint_name]
UNIQUE [CLUSTERED | NONCLUSTERED](col_name [, col_name2 [..., col_name16]])
[ON segment_name]
[NOT FOR REPLICATION]
|
FOREIGN KEY
|
[CONSTRAINT constraint_name]
[FOREIGN KEY (col_name [, col_name2 [..., col_name16]])]
REFERENCES [owner.]ref_table [(ref_col [, ref_col2 [..., ref_col16]])]
[ON DELETE CASCADE]
|
[CONSTRAINT constraint_name]
[FOREIGN KEY (col_name [, col_name2 [..., col_name16]])]
REFERENCES [owner.]ref_table [(ref_col [, ref_col2 [..., ref_col16]])]
[NOT FOR REPLICATION]
|
DEFAULT
|
Column property, not a constraint
DEFAULT (constant_expression)
|
[CONSTRAINT constraint_name]
DEFAULT {constant_expression | niladic-function | NULL}
[FOR col_name]
[NOT FOR REPLICATION]
|
CHECK
|
[CONSTRAINT constraint_name]
CHECK (expression)
|
[CONSTRAINT constraint_name]
CHECK [NOT FOR REPLICATION] (expression)
|
NOT FOR REPLICATION子句用来在复制过程中挂起列级别,FOREIGN KEY,以及CHECK约束。
外部键
定义外部关键字的语法在各种RDBMS中都是相似的。在外部关键字中标明的列数和每一列的数据类型必须和REFERENCES子句相匹配。一个输入到列中的非空的值必须在REFERENCES子句中定义表和列中存在,并且被提及的表的列必须有一个PRIMARY KEY或者UNIQUE约束。
Microsoft SQL Server约束提供了在同一个数据库中引用表的能力。要实现在数据库范围的应用完整性,可以使用基于表的触发器。
Oracle和SQL Server都支持自引用表,这种表中有对同一个表的一列或几列的引用。例如,CLASS表中的prereq列可以引用CLASS表中的ccode列以确保一个有效的课程编号是作为一个子句的先决条件输入的。
在Oracle中实现层叠式的删除和修改是使用CASCADE DELETE子句,而SQL Server用表触发器来实现同样的功能。如果需要了解更多的信息,请参看本章后面的“SQL语言支持”部分 。
用户定义的完整性
用户定义的完整性允许你定义特定的商业规则,该规则不属于其他完整性的范畴。
存储过程
Microsoft SQL Server存储程序用CREATE PROCEDURE语句来接受或者返回用户提供的参数。除临时存储程序以外,存储程序是在当前数据库中创建的。下表显示了Oracle和SQL Server的语法。
Oracle
|
Microsoft SQL
|
CREATE OR REPLACE PROCEDURE [user.]procedure
[(argument [IN | OUT] datatype
[, argument [IN | OUT] datatype]
{IS | AS} block
|
CREATE PROC[EDURE] procedure_name [;number]
[
{@parameter data_type} [VARYING] [= default] [OUTPUT]
]
[,…n]
[WITH
{ RECOMPILE | ENCRYPTION |
RECOMPILE, ENCRYPTION} ]
[FOR REPLICATION]
AS
sql_statement […n]
|
在SQL Server中,临时存储程序是在tempdb数据库中通过在procedure_name前加上数字标记来创建的。加一个数字标记(#procedure_name)表示是一个本地临时存储程序,加两个数字标记(##procedure_name)表示是一个全局临时程序。
一个本地临时程序只能被创建它的用户使用。执行本地临时程序的许可不能授予其他用户。本地临时程序在用户会话结束时自动删除。
一个全局的临时程序可以被所有的SQL Server用户使用。如果一个全局临时程序被创建了,所有的用户都可以访问它,并且不能显式的撤回许可。全局临时程序在最后一个用户会话结束的时候自动删除。
SQL Server存储程序可以有最多32级嵌套。嵌套层数在被调用的程序开始执行时增加,在被调用的程序结束运行时减少。
下面的例子说明了怎样用一个Transact-SQL存储程序来代替一个Oracle的PL/SQL封装函数。Transact-SQL的版本更简单一些,因为SQL Server的返回结果的能力是在一个存储程序中直接用SELECT语句设置的,不需要使用游标。
Oracle
|
Microsoft SQL
|
CREATE OR REPLACE PACKAGE STUDENT_ADMIN.P1 AS ROWCOUNT NUMBER :=0;
CURSOR C1 RETURN STUDENT%ROWTYPE;
FUNCTION SHOW_RELUCTANT_STUDENTS
(WORKVAR OUT VARCHAR2) RETURN NUMBER;
END P1;
/
CREATE OR REPLACE PACKAGE BODY STUDENT_ADMIN.P1 AS CURSOR C1 RETURN STUDENT%ROWTYPE IS
SELECT * FROM STUDENT_ADMIN.STUDENT
WHERE NOT EXISTS
(SELECT 'X' FROM STUDENT_ADMIN.GRADE
WHERE GRADE.SSN=STUDENT.SSN) ORDER BY SSN;
FUNCTION SHOW_RELUCTANT_STUDENTS
(WORKVAR OUT VARCHAR2) RETURN NUMBER IS
WORKREC STUDENT%ROWTYPE;
BEGIN
IF NOT C1%ISOPEN THEN OPEN C1;
ROWCOUNT :=0;
ENDIF;
FETCH C1 INTO WORKREC;
IF (C1%NOTFOUND) THEN
CLOSE C1;
ROWCOUNT :=0;
ELSE
WORKVAR := WORKREC.FNAME||' '||WORKREC.LNAME||
', social security number '||WORKREC.SSN||' is not enrolled
in any classes!';
ROWCOUNT := ROWCOUNT + 1;
ENDIF;
RETURN(ROWCOUNT);
|
CREATE PROCEDURE
STUDENT_ADMIN.SHOW_
RELUCTANT_STUDENTS
AS SELECT FNAME+'' +LNAME+', social security number'+ SSN+' is not enrolled in any classes!'
FROM STUDENT_ADMIN.STUDENT S
WHERE NOT EXISTS
(SELECT 'X' FROM STUDENT_ADMIN.GRADE G
WHERE G.SSN=S.SSN)
ORDER BY SSN
RETURN@@ROWCOUNT
GO
|
EXCEPTION
WHEN OTHERS THEN
IF C1%ISOPEN THEN CLOSE C1;
ROWCOUNT :=0;
ENDIF;
RAISE_APPLICATION_ERROR(-20001,SQLERRM);
END SHOW_RELUCTANT_STUDENTS;
END P1;
/
|
|
SQL Server不支持与Oracle包或者函数相似的构造,也不支持在创建存储程序时的CREATE OR REPLACE选项。
延迟存储过程的执行
Microsoft SQL Server提供了WAITFOR,允许开发人员给定一个时间,时间段,或者事件来触发一个语句块、存储程序或者事务的执行。这是Transact-SQL对于Oracle中dbms_lock_sleep的等价。
WAITFOR {DELAY 'time' | TIME 'time'}
指示Microsoft SQL Server等待直到给定的时间过去以后再执行,最多可以到24小时。
在这里
指示Microsoft SQL Server等待,直到给定数量的时间过去以后才执行,最多可以设置到24小时。
需要等待的时间,时间可以是任何可接受的datetime数据类型的格式,或者可以作为一个本地变量给出。但是,不能指定datetime值的日期部分。
指示SQL Server等到指定的时间
例如:
BEGIN
WAITFOR TIME '22:20'
EXECUTE update_all_stats
END
|
指定存储程序中的参数
要在一个存储程序中指定一个参数,可以使用下面给出的语法。
Oracle
|
Microsoft SQL
|
Varname datatype
DEFAULT <value>;
|
{@parameter data_type} [VARYING]
[= default] [OUTPUT]
|
触发器(Triggers)
Oracle和Microsoft SQL Server都有触发器,但它们在执行上有些不同。
描述
|
Oracle
|
Microsoft SQL Server
|
每表可以有的触发器数
|
无限制
|
无限制
|
在INSERT, UPDATE, DELETE之前执行触发器
|
是
|
否
|
在INSERT, UPDATE, DELETE之后执行触发器
|
是
|
是
|
语句级触发器
|
有
|
有
|
行级触发器
|
有
|
无
|
在执行之前检查约束
|
是,除非触发器被取消
|
是。另外,这是DTS(Data Transformation Services)中的一个选项
|
在一个UPDATE或者DELETE触发器中提交旧的或者以前的值
|
:old
|
DELETED.column
|
在INSERT触发器中提交新值
|
:new
|
INSERTED.column
|
取消触发器
|
ALTER TRIGGER
|
DTS中的选项
|
DELETED和INSERTED是SQL Server为触发器创建的概念上的表。该表在结构上同触发器定义于其上的表相似,并且保存了可能被用户的行动改变的旧的或者新的行中的值。该表将跟踪在Transact-SQL
给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow
|