把Oracle数据库移植到Microsoft SQL Server 7.0(4)
下表提供了一个用来定义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 [...,
[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都支持自引用表,这种表中有对同一个表的一列或几列的引用。例如
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]
]
[,…n]
[WITH
{ RECOMPILE ENCRYPTION
RECOMPILE, ENCRYPTION} ]
[FOR REPLICATION]
AS
sql_statement […n]
在SQL Server中,临时存储程序是在tempdb数据库中通过在procedure_name前加上数字标
个数字标记(#procedure_name)表示是一个本地临时存储程序,加两个数字标记(
是一个全局临时程序。
一个本地临时程序只能被创建它的用户使用。执行本地临时程序的许可不能授予其他用户
用户会话结束时自动删除。
一个全局的临时程序可以被所有的SQL Server用户使用。如果一个全局临时程序被创建了
以访问它,并且不能显式的撤回许可。全局临时程序在最后一个用户会话结束的时候自动
SQL Server存储程序可以有最多32级嵌套。嵌套层数在被调用的程序开始执行时增加,在
运行时减少。
下面的例子说明了怎样用一个Transact-SQL存储程序来代替一个Oracle的PL/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
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'
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
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包或者函数相似的构造,也不支持在创建存储程序时的
延迟存储过程的执行
Microsoft SQL Server提供了WAITFOR,允许开发人员给定一个时间,时间段,或者事件
存储程序或者事务的执行。这是Transact-SQL对于Oracle中dbms_lock_sleep的等价。
WAITFOR {DELAY 'time' TIME 'time'}
指示Microsoft SQL Server等待直到给定的时间过去以后再执行,最多可以到24小时。
在这里
DELAY
指示Microsoft SQL Server等待,直到给定数量的时间过去以后才执行,最多可以设置到
'time'
需要等待的时间,时间可以是任何可接受的datetime数据类型的格式,或者可以作为一个
但是,不能指定datetime值的日期部分。
TIME
指示SQL Server等到指定的时间
例如:
BEGIN
WAITFOR TIME '22:20'
EXECUTE update_all_stats
END
指定存储程序中的参数
要在一个存储程序中指定一个参数,可以使用下面给出的语法。
Oracle Microsoft SQL
Varname datatype DEFAULT
[= default] [OUTPUT]
触发器(Triggers)
Oracle和Microsoft SQL Server都有触发器,但它们在执行上有些不同。
描述 Oracle Microsoft SQL Server
每表可以有的触发器数 无限制 无限制
在INSERT, UPDATE, DELETE之前执行触发器 是 否
在INSERT, UPDATE, DELETE之后执行触发器 是 是
语句级触发器 有 有
行级触发器 有 无
在执行之前检查约束 是,除非触发器被取消 是。另外,这是DTS(Data
一个选项
在一个UPDATE或者DELETE触发器中提交旧的或者以前的值 :old DELETED.column
在INSERT触发器中提交新值 :new INSERTED.column
取消触发器 ALTER TRIGGER DTS中的选项
DELETED和INSERTED是SQL Server为触发器创建的概念上的表。该表在结构上同触发器定
并且保存了可能被用户的行动改变的旧的或者新的行中的值。该表将跟踪在Transact-SQL
这些表提供了与Oracle中的行级别的触发器同样的功能。当一个INSERT、UPDATE、或者
Server中执行的时候,行被加入到触发器表中,而且是同时加入到INSERTED和DELETED表
INSERTED和DELETED表同触发器表是一样的。它们有同样的列名和数据类型。例如,如果
个触发器,那么INSERTED和DELETED就有这样的结构。
GRADE INSERTED DELETED
SSN CHAR(9)
CCODE VARCHAR(4)
GRADE VARCHAR(2) SSN CHAR(9)
CCODE VARCHAR(4)
GRADE VARCHAR(2) SSN CHAR(9)
CCODE VARCHAR(4)
GRADE VARCHAR(2)
INSERTED和DELETED表可以被触发器检查以确定要执行什么样的触发器行动。INSERTED表
语句一起使用。DELETED表则和DELETE以及UPDATE语句一起使用。
UPDATE语句使用INSERTED和DELETED表,这是因为进行UPDATE操作时,SQL Server总是要
新的行。因此,执行UPDATE时,INSERTED表中的行总是DELETED表中的行的副本。
下面的例子使用INSERTED和DELETED表来代替PL/SQL中的行级别的触发器。一个完全的外
询任意表中的所有行。
Oracle Microsoft SQL Server
CREATE TRIGGER STUDENT_ADMIN.TRACK_GRADES
AFTER
INSERT OR UPDATE OR DELETE
ON STUDENT_ADMIN.GRADE
FOR EACH ROW
BEGIN
INSERT INTO GRADE_HISTORY(
TABLE_USER, ACTION_DATE,
OLD_SSN, OLD_CCODE,
OLD_GRADE, NEW_SSN,
NEW_CCODE, NEW_GRADE)
VALUES (USER, SYSDATE,
:OLD.SSN, :OLD.CCODE,
:OLD.GRADE, :NEW.SSN,
:NEW.CCODE, :NEW.GRADE),
END;
CREATE TRIGGER STUDENT_ADMIN.TRACK_GRADES
ON STUDENT_ADMIN.GRADE
FOR INSERT, UPDATE, DELETE
AS
INSERT INTO GRADE_HISTORY(
TABLE_USER, ACTION_DATE,
OLD_SSN, OLD_CCODE, OLD_GRADE
NEW_SSN, NEW_CCODE, NEW_GRADE)
SELECT USER, GETDATE(),
OLD.SSN, OLD.CCODE, OLD.GRADE,
NEW.SSN, NEW.CCODE, NEW.GRADE
FROM INSERTED NEW FULL OUTER JOIN
DELETED OLD ON NEW.SSN = OLD.SSN
你可以只在当前数据库中创建一个触发器,你也可以引用当前数据库之外的对象。如果你
修饰触发器,那么就用同样的方法来修饰表名。
触发器可以最多嵌套32级。如果一个触发器改变了某个表,而该表有另外一个触发器,则
动的,可以调用第三个触发器,如此类推。如果链上的任何触发器引起了死循环,则嵌套
器被取消。此外,如果某表结果上的一行上的一个更新触发器同时是另一行的更新,那么
行一次。
Microsoft SQL Server的公布引用完整性(declarative referential integrity,DRI)
的引用完整性定义。如果需要跨数据库的完整性,可以使用触发器。
下面的语句在Transact-SQL触发器中是不被允许的。
CREATE 语句(DATABASE, TABLE, INDEX, PROCEDURE, DEFAULT, RULE, TRIGGER,
DROP 语句(TRIGGER, INDEX, TABLE, PROCEDURE, DATABASE, VIEW, DEFAULT, RULE)
ALTER 语句(DATABASE, TABLE, VIEW, PROCEDURE, TRIGGER)
TRUNCATE TABLE
GRANT, REVOKE, DENY
UPDATE STATISTICS
RECONFIGURE
UPDATE STATISTICS
RESTORE DATABASE, RESTORE LOG
LOAD LOG, DATABASE
DISK语句
SELECT INTO (因为它创建一个表)
如果需要了解关于触发器的更多信息,请参看SQL Server联机手册。
事务、锁定和并行
本部分解释了在Oracle和Microsoft SQL Server事务是如何执行的,并且提供了所有数据
和并行问题之间的区别。
事务
在Oracle中,执行插入、更新或者删除操作时自动开始事务。一个应用程序必须给出一个
数据库的所有修改。如果没有执行COMMIT,所有的修改都将后滚或者自动变成未完成的。
缺省情况下,Microsoft SQL Server在每次插入、更新或者删除操作之后自动执行一个
据是自动保存的,你不能后滚任何改变。你可以使用隐式的或者显式的事务模式来改变这
隐式的事务模式允许SQL Server像Oracle一样运转,这种模式是用SET IM
的。如果该选项是ON并且当前没有突出的事务,则每一个SQL语句自动开始一个事务。如
务,则不会有任何新的事务开始。打开的事务必须由用户用COMMIT TRANSACTION语句来显
有的改变生效并且释放所有的锁定。
一个显明的事务是一组由下述事务分隔符包围的SQL语句:
BEGIN TRANSACTION [transaction_name]
COMMIT TRANSACTION [transaction_name]
ROLLBACK TRANSACTION [transaction_name savepoint_name]
在下面这个例子中,英语系被改变为文学系。请注意BEGIN TRANSACTION和COMMIT
Oracle Microsoft SQL
INSERT INTO DEPT_ADMIN.DEPT (DEPT, DNAME)
VALUES ('LIT', 'Literature')
/
UPDATE DEPT_ADMIN.CLASS
SET MAJOR = 'LIT'
WHERE MAJOR = 'ENG'
/
UPDATE STUDENT_ADMIN.STUDENT
SET MAJOR = 'LIT'
WHERE MAJOR = 'ENG'
/
DELETE FROM DEPT_ADMIN.DEPT
WHERE DEPT = 'ENG'
/
COMMIT
/ BEGIN TRANSACTION
INSERT INTO DEPT_ADMIN.DEPT (DEPT, DNAME)
VALUES ('LIT', 'Literature')
UPDATE DEPT_ADMIN.CLASS
SET DEPT = 'LIT'
WHERE DEPT = 'ENG'
UPDATE STUDENT_ADMIN.STUDENT
SET MAJOR = 'LIT'
WHERE MAJOR = 'ENG'
DELETE FROM DEPT_ADMIN.DEPT
WHERE DEPT = 'ENG'
COMMIT TRANSACTION
GO
所有显明的事务必须用BEGIN TRANSACTION...COMMIT TRANSACTION语句封闭。SAVE
同Oracle中的SAVEPOINT命令是一样的,在事务中设置一个保存点,这样就可以进行部分
了。
事务可以嵌套。如果出现了这种情况,最外层的一对创建并提交事务,内部的对跟踪嵌套
套的事务时,@@TRANCOUNT函数就增加。通常,这种显然的事务嵌套发生在存储程序或者
互相调用的触发器中。尽管事务可以嵌套,但是对ROLLBACK TRANSACTION语句的行为的影
在存储过程和触发器中,BEGIN TRANSACTION语句的个数必须和COMMIT TRANSACTION语句
不匹配的BEGIN TRANSACTION和COMMIT TRANSACTION语句的存储过程和触发器在运行的时
息。语法允许在一个事务中调用包含BEGIN TRANSACTION和COMMIT TRANSACTION语句对的
只要情况许可,就应该把一个大的事务分成几个较小的事务。确保每个事务都在一个单独
定义。为了把可能的并行冲突减到最小,事务既不应该跨越多个batch,也不应该等待用
组合到一个运行时间较长的事务中会给恢复时间带来消极的影响,并且还会造成并行问题
在使用ODBC编程的时候,你可以通过使用SQLSetConnectOption函数来选择显式或者隐式
选择哪种模式要视AUTOCOMMIT连接选项的情况而定。如果AUTOCOMMIT是ON(缺省的),你
如果AUTOCOMMIT是OFF,则在隐式模式下。
如果你通过SQL Server Query Analyzer或者其他查询工具使用脚本,你可以显式的包括
BEGIN TRANSACTION语句,也可以利用SET IMPLICIT_TRANSACTIONS ON语句来开始脚本。
的方法更灵活一些,而隐式的方法更适合Oracle。
锁定和事务孤立
Oracle和Microsoft SQL Server有着很不一样的锁定和孤立策略。当你把Oracle应用程序
应用程序的时候,你必须考虑到这些不同以确保应用程序的可伸缩性。
Oracle对所有读数据的SQL语句隐式或者显式的使用一种多版本一致模型(
)。在这种模型中,数据读者在读数据行以前,缺省的既不获得一个锁定也不等待其他的
需要一个已经改变但别的写入者还没有提交的数据时,Oracle通过使用后滚段来重建一个
法来重新创建旧的数据。
Oracle中的数据写入者在更新、删除或者插入数据时要请求锁定。锁定将一直维持到事务
的用户覆盖尚未提交的修改。
Microsoft SQL Server使用多粒度锁定,该锁定允许用事务来锁定不同类型的资源。为了
最低,SQL Server自动在与任务相配的层次上锁定资源。以较小的间隔尺寸锁定,例如行
是管理开销较大,因为如果有许多行锁定,就必须维持多个锁定。以较大的间隔尺寸锁定
方面是昂贵的,因为对整个表的锁定限制了其他事务对表中任何一部分的访问,但是管理
为只要维持少数几个锁定。SQL Server可以锁定这些资源(按照间隔尺寸递增的顺序排列
资源 描述
RID 行标识符。用于一个单行表的独立锁定。
Key 键;索引中的一个行锁定。用于在一个可串行化的事务中保护键范围。
Page 8-KB数据页或者索引页。
Extent 相邻的八个数据页或者索引页的组。
Table 整个表,包括所有数据和索引。
DB 数据库。
SQL Server使用不同的锁定模式锁定资源,使用哪种模式决定了当前事务访问如何访问资
锁定模式 描述
Shared (S) 用于那些不修改或者更新数据的操作(只读操作),例如一个SELECT语句。
Update (U) 用于那些可以被更新的资源。防止当多个会话被读入、锁定,然后潜在的更
公共形式的死锁。
Exclusive (X) 用于数据修改操作,例如UPDATE、INSERT、或者DELETE。确保不会同时发
多个修改操作。
Intent 用于建立一个锁定层次。
Schema 在一个依靠表的模式的操作执行时使用。有两种类型的模式锁定:schema
schema modification (Sch-M)。
对于任何RDBMS都很重要的一点是,快速释放锁定以提供最大的并行性。你可以通过尽可
务来确保快速释放锁定。如果可能的话,事务不应该跨越多个往返行程到服务器,也不应
的时间。如果你使用游标,你也应该使你的应用程序很快提取数据,因为未提取数据的扫
据共享锁定,因此将阻碍更新。欲了解更多信息,请参看本章后面的“使用ODBC”部分。
改变缺省的锁定行为
Microsoft SQL Server和Oracle都允许开发人员使用非缺省的锁定和孤立行为。在Oracle
是SELECT 命令的FOR UPDATE子句,SET TRANSACTION READ ONLY命令,以及显式的LOCK
因为两者的锁定和孤立策略如此不同,所以很难在Oracle和SQL Server之间直接映射锁定
解这一过程,重要的一点是理解SQL Server提供的修改缺省锁定行为的选择。
在SQL Server中,修改缺省锁定行为最常用的机制是SET TRANSACTION ISOLATION LEVEL
UPDATE语句中支持的锁定暗示。SET TRANSACTION ISOLATION LEVEL语句为一个用户会话
务孤立级别。除非在一个SQL语句的FROM子句中标明了表级别的锁定暗示,否则这将变成
事务孤立是这样设定的:
SET TRANSACTION ISOLATION LEVEL
{
READ COMMITTED
READ UNCOMMITTED
REPEATABLE READ
SERIALIZABLE
}
READ COMMITTED
缺省的SQL Server孤立级别。如果你使用这种选择,你的应用程序将不能读取其他事务还
在这种模式下,一旦数据从页上读出,仍然要释放共享锁定。如果应用程序在同一个事务
的数据区,将会看到别的用户做的修改。
SERIALIZABLE
如果设定了这种选择,事务将同其他事务孤立起来。如果你不希望在查询中看到其他用户
设置事务的孤立级别为SERIALIZABLE。SQL Server将占据所有的共享锁定,直到事务结束
SELECT语句中表名的后面使用HOLDLOCK暗示来在一个更小的级别上取得同样的效果。
READ UNCOMMITTED
如果设定为这种选择,SQL Server读者将不会受到阻塞,就像在Oracle中一样。该选择实
说是孤立级别为0的锁定,这意味着不使用任何共享锁定并且也不使用任何独占的锁定。
有可能会读到未提交的或者污损的数据;在事务结束以前,数据可能会改变,数据集中的
消失。这个选项同一个事务中在所有SELECT语句中设定所有的表为NOLOCK的效果是一样的
别中限制性最小的一种。只有在你已经彻底的搞清楚了它将对你的应用程序结果的精确度
前提下才能使用这种选择。
SQL Server有两种方法实现Oracle中的READ ONLY功能:
如果一个应用程序中的事务需要可重复读取的行为,你也许需要使用SQL Server提供的
别。
如果所有的数据库访问都是只读的,你可以设置SQL Server数据库选项为READ ONLY来提
SELECT…FOR UPDATE
当一个应用程序利用WHERE CURRENT OF 语法来在一个游标上实现定位更新或者删除时,
SELECT…FOR UPDATE语句。在这种情况下,可以随意去掉FOR UPDATE子句,因为
的缺省行为是“可更新的”。
缺省情况下,SQL Server游标在提取行下不占据锁定。SQL Server使用一种乐观的并行策
concurrency strategy)来防止更新时相互之间的覆盖。如果一个用户试图更新或者删除
经被修改过的行,SQL Server将给出一个错误消息。应用程序可以捕获该消息,并且重新
者删除。要改变这个行为,开发人员可以在游标声明中使用SCROLL_LOCKS。
通常情况下,乐观的并行策略支持较高的并行性,所谓通常情况是指更新器之间冲突很少
应用程序确实需要保证一行在被提取以后不会被修改,你可以在SELECT语句中使用
会阻碍别的读者,但是它禁止其他潜在的写入者也获得该数据的更新锁定。使用ODBC时,
SQLSETSTMTOPTION (…,SQL_CONCURRENCY)= SQL_CONCUR_LOCK来达到同样的目的。但是,
将减少并行性。
表级别的锁定
Microsoft SQL Server可以用SELECT…table_name (TABLOCK)语句来锁定整个表。这和
TABLE…IN SHARE MODE语句是一样的。该锁定允许其他人读取一个表,但是禁止他们修改
锁定将维持到语句的结束。如果你同时加上了HOLDLOCK关键字(SELECT…table_name
表的锁定将一直维持到事务的结束。
可以用SELECT…table_name (TABLOCKX)语句在一个SQL Server表上设置一个独占的锁定
上的独占锁定。该锁定禁止其他人读取和修改该表,并且将一直维持到命令或者事务结束
TABLE…IN EXCLUSIVE MODE语句的功能是一样的。
SQL Server没有为显式的锁定请求提供NOWAIT选项。
。
锁定升级
当一个查询向表请求行时,Microsoft SQL Server自动生成一个页级别的锁定。但是,如
大部分行时,SQL Server将把锁定从页级别升级到表级别。这个过程叫做锁定升级。
锁定增加使那些产生较大结果集的表的扫描和操作更加有效,因为它减少了锁定的管理开
的SQL语句一般都要造成锁定增加。
在读取操作中,如果一个共享页级别的锁定增加为一个表锁定时,将应用一个共享表锁定
列情况下应用共享的表级别的锁定:
使用了HOLDLOCK或者SET TRANSACTION ISOLATION LEVEL SERIALIZABLE语句。
优化器选择了一个表的扫描。
表中积累的共享锁定的数目超过锁定升级的极限。
表中缺省的锁定升级的极限是200页,但是该极限可以用最小和最大范围定制为依赖于表
欲了解关于锁定升级极限的更多信息,请参看SQL Server联机手册。
在一个写操作中,当一个UPDATE锁定被升级为一个表锁定时,应用一个独占表锁定(
在下列情况下使用:
更新或者删除操作无索引可用。
表中有独占锁定的页的数目超过锁定升级上限。
创建了一个分簇的索引。
Oracle不能升级行级别的锁定,这将导致一些包含了FOR UPDATE子句的查询出问题。例如
100,000行数据,并且一个Oracle用户给出下列语句:
SELECT * FROM STUDENT FOR UPDATE
这个语句强制Oracle RDBMS依次锁定STUDENT表的一行;这将花去一段时间。它永远也不
个表。
在SQL Server同样的查询是:
SELECT * FROM STUDENT (UPDLOCK)
当这个查询运行的时候,页级别的锁定升级为表级别的锁定,后者更加有效并且明显要快
死锁
当一个进程锁定了另一个进程需要的页或者表的时候,而第二个进程又锁定了第一个进程
时候就会发生死锁。死锁也叫抱死。SQL Server自动探测和解决死锁。如果找到一个死锁
成了抱死的用户进程。
在每次数据修改之后,你的程序代码需要检查1205号消息,这个消息指出一个死锁。如果
说明发生了一个死锁并且事务已经后滚。在这种情况下,你的应用程序必须重新开始这个
死锁一般可以通过一些简单的技术加以避免:
在你的应用程序的各部分以同样的顺序访问表。
在每个表上使用分簇的索引以强制一个显式的行顺序。
使事务简短。
欲了解详细信息,请参阅Microsoft Knowledge Base文章“Detecting and Avoiding
Microsoft SQL Server”
远程事务
在Oracle中执行远程事务,你必须通过一个数据库连接访问远程数据库节点。在SQL
问一个远程服务器。远程服务器是一台运行SQL Server的服务器,用户可以用他们的本地
务器。当某个服务器被设置为远程服务器,用户就可以在其上使用系统过程和存储过程而
录到上面。
远程服务器是成对设置的。你必须配置两台服务器,使它们互相把对方当作远程服务器。
字都必须用sp_addlinkedserver系统存储过程或者SQL Server Enterprise Manager加到
设置完远程服务器以后,你可以用sp_addremotelogin系统存储过程或者SQL Server
来为那些必须访问远程服务器的用户设置远程登录账号。在这一步完成以后,你还必须赋
过程的权限。
然后用EXECUTE语句来在远程服务器上执行过程。这个例子在远程服务器STUDSVR1上执行
存储过程,并且将指明成功或者失败的返回情况存储在@retvalue1中:
DECLARE @retvalue1 int
EXECUTE @retvalue = STUDSVR1.student_db.student_admin.validate_student
欲了解详细信息,请参看SQL Server联机手册。
分布事务
如果修改两个或者更多的数据库节点上的表,Oracle就自动初始化一个分布式事务。SQL
用包含在SQL Server中的微软分布事务协调器(Microsoft Distributed Transaction
中的两步提交服务(two-phase commit services)。
缺省情况下,SQL Server必须被通知参与分布事务。SQL Server参与一个MS DTC事务可以
种来存储:
BEGIN DISTRIBUTED TRANSACTION语句。该语句开始一个新的MS DTC事务。
一个客户端应用程序直接调用DTC事务接口。
在下例中,注意对本地表GRADE和远程表CLASS的分布式更新(使用一个class_name过程
BEGIN DISTRIBUTED TRANSACTION
UPDATE STUDENT_ADMIN.GRADE
SET GRADE = 'B+' WHERE SSN = '111111111' AND CCODE = '1234'
DECLARE @retvalue1 int
EXECUTE @retvalue1 = CLASS_SVR1.dept_db.dept_admin.class_name '1234',
COMMIT TRANSACTION
GO
如果程序不能完成事务,则通过ROLLBACK TRANSACTION语句终止该事务。如果程序失败或
失败,MS DTC终止该事务。MS DTC不支持分布式的存储点或者是SAVE TRANSACTION语句。
失败或者后滚,则整个事务退回到分布式事务的起点,而不理会任何存储点。
两步提交处理
Oracle和MS DTC两步提交机制在操作上是相似的。在SQL Server两步提交的第一步,事务
与的资源管理器准备提交。如果有任何资源管理器没有准备好,事务管理器就向与事务相
个异常中断决定。
如果所有的资源管理器都能成功的准备,事务管理器就广播一个提交决定。这是提交处理
源管理器准备好后,事务究竟是提交了还是失败了,这一点还是拿不准。MS DTC维持了一
它的提交或者中断决定都是持久的。如果某个资源管理器或者事务管理器失败了,则当它
候,就能在那个拿不准的事务上协调了。
SQL语言支持
本部分简要介绍了Transact-SQL和PL/SQL语言语法上的相似和不同之处,并且给出了转换
SELECT和数据操作声明
当你把Oracle DML语句和PL/SQL程序移植到SQL Server上时,请按下列步骤进行:
检查所有SELECT、INSERT、UPDATE、和DELETE语句是否有效。做任何需要的修改。
把所有的外部节点改为SQL-92外部节点语法
用适当的SQL Server函数代替Oracle函数
检查所有的比较操作符
用“+”代替“”做字符串串联操作符。
用Transact-SQL程序代替PL/SQL程序
把所有的PL/SQL游标改为无游标SELECT语句或者Transact-SQL游标。
用Transact-SQL过程代替PL/SQL过程、函数和封装。
把PL/SQL触发器转换为Transact-SQL触发器。
使用SET SHOWPLAN语句来调试你的查询以获得高的性能。
SELECT statements语句
Oracle和Microsoft SQL Server用的SELECT语句的语法是类似的。
Oracle Microsoft SQL
SELECT [/*+ optimizer_hints*/]
[ALL DISTINCT] select_list
[FROM
{table_name view_name select_statement}]
[WHERE clause]
[GROUP BY group_by_expression]
[HAVING search_condition]
[START WITH … CONNECT BY]
[{UNION UNION ALL INTERSECT
MINUS} SELECT …]
[ORDER BY clause]
[FOR UPDATE] SELECT select_list
[INTO new_table_]
FROM table_source
[WHERE search_condition]
[ GROUP BY [ALL] group_by_expression [,…n]
[ WITH { CUBE ROLLUP } ]
[HAVING search_condition]
[ORDER BY order_expression [ASC DESC] ]
In addition:
UNION Operator
COMPUTE Clause
FOR BROWSE Clause
OPTION Clause
SQL Server不支持面向Oracle的基于开销的优化器暗示,必须把这些暗示清除掉。建议使
于开销的优化器。欲了解详细信息,请参阅本章后面的“调试SQL语句”部分。
SQL Server不支持Oracle的START WITH…CONNECT BY子句。在SQL Server中,你可以用创
务的存储过程来代替。
SQL Server不支持Oracle的INTERSECT和MINUS集合。SQL Server的EXISTS和NOT EXISTS子
任务。
下面的例子使用INTERSECT操作符来为所有有学生的班级找到课程代码和课程名称。注意
代替INTERSECT操作符的。两者返回的数据是一样的。
Oracle Microsoft SQL
SELECT CCODE, CNAME
FROM DEPT_ADMIN.CLASS
INTERSECT
SELECT C.CCODE, C.CNAME
FROM STUDENT_ADMIN.GRADE G,
DEPT_ADMIN.CLASS C
WHERE C.CCODE = G.CCODE SELECT CCODE, CNAME
FROM DEPT_ADMIN.CLASS C
WHERE EXISTS
(SELECT 'X' FROM STUDENT_ADMIN.GRADE G
WHERE C.CCODE = G.CCODE)
下例使用MINUS操作符来找出那些没有学生的班级。
Oracle Microsoft SQL
SELECT CCODE, CNAME
FROM DEPT_ADMIN.CLASS
MINUS
SELECT C.CCODE, C.CNAME
FROM STUDENT_ADMIN.GRADE G,
DEPT_ADMIN.CLASS C
WHERE C.CCODE = G.CCODE SELECT CCODE, CNAME
FROM DEPT_ADMIN.CLASSC
WHERE NOT EXISTS
(SELECT 'X' FROM STUDENT_ADMIN.GRADE G
WHERE C.CCODE = G.CCODE)
INSERT语句
Oracle和Microsoft SQL Server用的INSERT语句的语法是类似的。
Oracle Microsoft SQL
INSERT INTO
{table_name view_name select_statement} [(column_list)]
{values_list select_statement} INSERT [INTO]
{ table_name [ [AS] table_alias] WITH (
view_name [ [AS] table_alias]
rowset_function_limited
}
{ [(column_list)]
{ VALUES ( { DEFAULT
NULL
expression
}[,…n]
)
derived_table
execute_statement
}
}
DEFAULT VALUES
Transact-SQL语言支持插入表和视图,但是不支持SELECT语句中的INSERT操作。如果你的
了,则必须修改。
Oracle Microsoft SQL
INSERT INTO (SELECT SSN, CCODE, GRADE FROM GRADE)
VALUES ('111111111', '1111',NULL) INSERT INTO GRADE (SSN, CCODE, GRADE)
VALUES ('111111111', '1111',NULL)
Transact-SQL的values_list参数提供了SQL-92标准的关键字DEFAULT,但这个在Oracle
行插入操作的时候,这个关键字给出了要用到的列的缺省值。如果给定的列没有缺省值,
如果该列不允许NULL,则返回一个错误消息。如果该列是作为一个时间片数据类型定义的
续值。
关键字DEFAULT不能用于标识列。要产生下一个连续值,则有IDENTITY属性的列一定不能
者values_clause。你不一定非要用DEFAUL关键字来获得一列的缺省值。在Oracle中,如
column_list引用并且它有一个缺省值,则缺省值将放入列中。这是执行移植时最兼容的
一个有用的Transact-SQL选项(EXECute procedure_name)是执行一个过程并且用管道把
一个目标表或者视图。Oracle不允许你这样做。
UPDATE语句
因为Transact-SQL支持Oracle的UPDATE绝大多数语法,所以只需要很小的修改。
Oracle Microsoft SQL