在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
列是用一个用户定义数据类型定义的
SQLServer 使用在创建数据类型时指定的空值性。使用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),然后SQLServer指定它为NOT NULL。
引用完整性
下表提供了一个用来定义referential完整性约束的语法比较。
约束
Oracle
Microsoft SQLServer
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小时。
在这里
DELAY
指示Microsoft SQL Server等待,直到给定数量的时间过去以后才执行,最多可以设置到24小时。
'time'
需要等待的时间,时间可以是任何可接受的datetime数据类型的格式,或者可以作为一个本地变量给出。但是,不能指定datetime值的日期部分。
TIME
指示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 SQLServer
每表可以有的触发器数
无限制
无限制
在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中的行一级的变化。这些表提供了与Oracle中的行级别的触发器同样的功能。当一个INSERT、UPDATE、或者DELETE语句在SQL Server中执行的时候,行被加入到触发器表中,而且是同时加入到INSERTED和DELETED表中。
INSERTED和DELETED表同触发器表是一样的。它们有同样的列名和数据类型。例如,如果在GRADE表中放置一个触发器,那么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表同INSERT和UPDATE语句一起使用。DELETED表则和DELETE以及UPDATE语句一起使用。
UPDATE语句使用INSERTED和DELETED表,这是因为进行UPDATE操作时,SQL Server总是要删除旧的行,填入新的行。因此,执行UPDATE时,INSERTED表中的行总是DELETED表中的行的副本。
下面的例子使用INSERTED和DELETED表来代替PL/SQL中的行级别的触发器。一个完全的外部接合点被用来查询任意表中的所有行。
Oracle
Microsoft SQLServer
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, SCHEMA, 和VIEW)
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命令来保存数据库的所有修改。如果没有执行COMMIT,所有的修改都将后滚或者自动变成未完成的。
缺省情况下,Microsoft SQL Server在每次插入、更新或者删除操作之后自动执行一个COMMIT语句。因为数据是自动保存的,你不能后滚任何改变。你可以使用隐式的或者显式的事务模式来改变这个缺省行为。
隐式的事务模式允许SQL Server像Oracle一样运转,这种模式是用SET IMPLICIT_TRANSACTIONS ON语句激活的。如果该选项是ON并且当前没有突出的事务,则每一个SQL语句自动开始一个事务。如果有一个打开的事务,则不会有任何新的事务开始。打开的事务必须由用户用COMMIT TRANSACTION语句来显明的承诺,以使所有的改变生效并且释放所有的锁定。
一个显明的事务是一组由下述事务分隔符包围的SQL语句:
BEGIN TRANSACTION [transaction_name]
COMMIT TRANSACTION [transaction_name]
ROLLBACK TRANSACTION [transaction_name | savepoint_name]
在下面这个例子中,英语系被改变为文学系。请注意BEGIN TRANSACTION和COMMIT TRANSACTION语句的用法。
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 TRANSACTION语句的功能同Oracle中的SAVEPOINT命令是一样的,在事务中设置一个保存点,这样就可以进行部分后滚(roll back)了。
事务可以嵌套。如果出现了这种情况,最外层的一对创建并提交事务,内部的对跟踪嵌套层。当遇到一个嵌套的事务时,@@TRANCOUNT函数就增加。通常,这种显然的事务嵌套发生在存储程序或者有BEGIN…COMMIT对互相调用的触发器中。尽管事务可以嵌套,但是对ROLLBACK TRANSACTION语句的行为的影响是很小的。
在存储过程和触发器中,BEGIN TRANSACTION语句的个数必须和COMMIT TRANSACTION语句的个数相匹配。包含不匹配的BEGIN TRANSACTION和COMMIT TRANSACTION语句的存储过程和触发器在运行的时候会产生一个错误消息。语法允许在一个事务中调用包含BEGIN TRANSACTION和COMMIT TRANSACTION语句对的存储过程和触发器。
只要情况许可,就应该把一个大的事务分成几个较小的事务。确保每个事务都在一个单独的batch中有完整的定义。为了把可能的并行冲突减到最小,事务既不应该跨越多个batch,也不应该等待用户输入。把多个事务组合到一个运行时间较长的事务中会给恢复时间带来消极的影响,并且还会造成并行问题。
在使用ODBC编程的时候,你可以通过使用SQLSetConnectOption函数来选择显式或者隐式的事务模式。究竟该选择哪种模式要视AUTOCOMMIT连接选项的情况而定。如果AUTOCOMMIT是ON(缺省的),你就是在显式模式中。如果AUTOCOMMIT是OFF,则在隐式模式下。
如果你通过SQL Server Query Analyzer或者其他查询工具使用脚本,你可以显式的包括一个上面提到的BEGIN TRANSACTION语句,也可以利用SET IMPLICIT_TRANSACTIONS ON语句来开始脚本。BEGIN TRANSACTION的方法更灵活一些,而隐式的方法更适合Oracle。
锁定和事务孤立
Oracle和Microsoft SQL Server有着很不一样的锁定和孤立策略。当你把Oracle应用程序转化为SQL Server应用程序的时候,你必须考虑到这些不同以确保应用程序的可伸缩性。
Oracle对所有读数据的SQL语句隐式或者显式的使用一种多版本一致模型(multiversion consistency model)。在这种模型中,数据读者在读数据行以前,缺省的既不获得一个锁定也不等待其他的锁定解开。当读者需要一个已经改变但别的写入者还没有提交的数据时,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 stability (Sch-S)和schema modification (Sch-M)。
对于任何RDBMS都很重要的一点是,快速释放锁定以提供最大的并行性。你可以通过尽可能短的保持一个事务来确保快速释放锁定。如果可能的话,事务不应该跨越多个往返行程到服务器,也不应该包括用户“思考”的时间。如果你使用游标,你也应该使你的应用程序很快提取数据,因为未提取数据的扫描将在服务器上占据共享锁定,因此将阻碍更新。欲了解更多信息,请参看本章后面的“使用ODBC”部分。
改变缺省的锁定行为
Microsoft SQL Server和Oracle都允许开发人员使用非缺省的锁定和孤立行为。在Oracle中,最普通的机制是SELECT 命令的FOR UPDATE子句,SET TRANSACTION READ ONLY命令,以及显式的LOCK TABLE命令。
因为两者的锁定和孤立策略如此不同,所以很难在Oracle和SQL Server之间直接映射锁定选择。要更好的理解这一过程,重要的一点是理解SQL Server提供的修改缺省锁定行为的选择。
在SQL Server中,修改缺省锁定行为最常用的机制是SET TRANSACTION ISOLATION LEVEL语句和在SELECT和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提供的SERIALIZABLE孤立级别。
如果所有的数据库访问都是只读的,你可以设置SQL Server数据库选项为READ ONLY来提高性能。
SELECT…FOR UPDATE
当一个应用程序利用WHERE CURRENT OF 语法来在一个游标上实现定位更新或者删除时,首先使用Oracle中的SELECT…FOR UPDATE语句。在这种情况下,可以随意去掉FOR UPDATE子句,因为Microsoft SQL Server游标的缺省行为是“可更新的”。
缺省情况下,SQL Server游标在提取行下不占据锁定。SQL Server使用一种乐观的并行策略(optimistic concurrency strategy)来防止更新时相互之间的覆盖。如果一个用户试图更新或者删除一个读入游标后已经被修改过的行,SQL Server将给出一个错误消息。应用程序可以捕获该消息,并且重新进行适当的更新或者删除。要改变这个行为,开发人员可以在游标声明中使用SCROLL_LOCKS。
通常情况下,乐观的并行策略支持较高的并行性,所谓通常情况是指更新器之间冲突很少的情况。如果你的应用程序确实需要保证一行在被提取以后不会被修改,你可以在SELECT语句中使用UPDLOCK暗示。这个暗示不会阻碍别的读者,但是它禁止其他潜在的写入者也获得该数据的更新锁定。使用ODBC时,你可以通过使用SQLSETSTMTOPTION (…,SQL_CONCURRENCY)= SQL_CONCUR_LOCK来达到同样的目的。但是,其他的任何选择都将减少并行性。
表级别的锁定
Microsoft SQL Server可以用SELECT…table_name (TABLOCK)语句来锁定整个表。这和Oracle的 LOCK TABLE…IN SHARE MODE语句是一样的。该锁定允许其他人读取一个表,但是禁止他们修改该表。缺省情况下,锁定将维持到语句的结束。如果你同时加上了HOLDLOCK关键字(SELECT…table_name (TABLOCK HOLDLOCK)),表的锁定将一直维持到事务的结束。
可以用SELECT…table_name (TABLOCKX)语句在一个SQL Server表上设置一个独占的锁定。该语句请求一个表上的独占锁定。该锁定禁止其他人读取和修改该表,并且将一直维持到命令或者事务结束。这同Oracle中TABLE…IN EXCLUSIVE MODE语句的功能是一样的。
SQL Server没有为显式的锁定请求提供NOWAIT选项。
锁定升级
当一个查询向表请求行时,Microsoft SQL Server自动生成一个页级别的锁定。但是,如果查询请求表中的大部分行时,SQL Server将把锁定从页级别升级到表级别。这个过程叫做锁定升级。
锁定增加使那些产生较大结果集的表的扫描和操作更加有效,因为它减少了锁定的管理开销。缺少WHERE子句的SQL语句一般都要造成锁定增加。
在读取操作中,如果一个共享页级别的锁定增加为一个表锁定时,将应用一个共享表锁定(TABLOCK)。在下列情况下应用共享的表级别的锁定:
使用了HOLDLOCK或者SET TRANSACTION ISOLATION LEVEL SERIALIZABLE语句。
优化器选择了一个表的扫描。
表中积累的共享锁定的数目超过锁定升级的极限。
表中缺省的锁定升级的极限是200页,但是该极限可以用最小和最大范围定制为依赖于表尺寸的一个百分比。欲了解关于锁定升级极限的更多信息,请参看SQL Server联机手册。
在一个写操作中,当一个UPDATE锁定被升级为一个表锁定时,应用一个独占表锁定(TABLOCKX)。独占表锁定在下列情况下使用:
更新或者删除操作无索引可用。
表中有独占锁定的页的数目超过锁定升级上限。
创建了一个分簇的索引。
Oracle不能升级行级别的锁定,这将导致一些包含了FOR UPDATE子句的查询出问题。例如,假设STUDENT表有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 Deadlocks in Microsoft SQL Server”
远程事务
在Oracle中执行远程事务,你必须通过一个数据库连接访问远程数据库节点。在SQL Server中,你必须访问一个远程服务器。远程服务器是一台运行SQL Server的服务器,用户可以用他们的本地服务器访问该服务器。当某个服务器被设置为远程服务器,用户就可以在其上使用系统过程和存储过程而不需要显式的登录到上面。
远程服务器是成对设置的。你必须配置两台服务器,使它们互相把对方当作远程服务器。每台服务器的名字都必须用sp_addlinkedserver系统存储过程或者SQL Server Enterprise Manager加到伙伴服务器上。
设置完远程服务器以后,你可以用sp_addremotelogin系统存储过程或者SQL Server Enterprise Manager来为那些必须访问远程服务器的用户设置远程登录账号。在这一步完成以后,你还必须赋予他们执行存储过程的权限。
然后用EXECUTE语句来在远程服务器上执行过程。这个例子在远程服务器STUDSVR1上执行了validate_student存储过程,并且将指明成功或者失败的返回情况存储在@retvalue1中:
DECLARE @retvalue1 int
EXECUTE @retvalue = STUDSVR1.student_db.student_admin.validate_student '111111111'
欲了解详细信息,请参看SQL Server联机手册。
分布事务
如果修改两个或者更多的数据库节点上的表,Oracle就自动初始化一个分布式事务。SQL Server分布式事务使用包含在SQL Server中的微软分布事务协调器(Microsoft Distributed Transaction Coordinator,MS DTC)中的两步提交服务(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', 'Basketweaving'
COMMIT TRANSACTION
GO
如果程序不能完成事务,则通过ROLLBACK TRANSACTION语句终止该事务。如果程序失败或者参与的资源管理器失败,MS DTC终止该事务。MS DTC不支持分布式的存储点或者是SAVE TRANSACTION语句。如果一个MS DTC事务失败或者后滚,则整个事务退回到分布式事务的起点,而不理会任何存储点。
两步提交处理
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 Server的基于开销的优化器。欲了解详细信息,请参阅本章后面的“调试SQL语句”部分。
SQL Server不支持Oracle的START WITH…CONNECT BY子句。在SQL Server中,你可以用创建一个执行同样任务的存储过程来代替。
SQL Server不支持Oracle的INTERSECT和MINUS集合。SQL Server的EXISTS和NOT EXISTS子句可以完成同样的任务。
下面的例子使用INTERSECT操作符来为所有有学生的班级找到课程代码和课程名称。注意EXISTS操作符是怎样代替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 ( <table_hint_limited> […n])
| 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程序这么做了,则必须修改。
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。如果该列不允许NULL,则返回一个错误消息。如果该列是作为一个时间片数据类型定义的,则插入下一个连续值。
关键字DEFAULT不能用于标识列。要产生下一个连续值,则有IDENTITY属性的列一定不能列入column_list或者values_clause。你不一定非要用DEFAUL关键字来获得一列的缺省值。在Oracle中,如果该列没有被column_list引用并且它有一个缺省值,则缺省值将放入列中。这是执行移植时最兼容的方法。
一个有用的Transact-SQL选项(EXECute procedure_name)是执行一个过程并且用管道把它的输出值输出到一个目标表或者视图。Oracle不允许你这样做。
UPDATE语句
因为Transact-SQL支持Oracle的UPDATE绝大多数语法,所以只需要很小的修改。
Oracle
Microsoft SQL
UPDATE
{table_name | view_name | select_statement}
SET [column_name(s) = {constant_value | expression | select_statement | column_list |
variable_list}
{where_statement}
UPDATE
{
table_name [ [AS] table_alias] WITH ( <table_hint_limited> […n])
view_name [ [AS] table_alias]
| rowset_function_limited
}
SET
{column_name = {expression | DEFAULT | NULL}
| @variable = expression
| @variable = column = expression } [,…n]
{{[FROM {<table_source>} [,…n] ]
[WHERE
<search_condition>] }
|
[WHERE CURRENT OF
{ { [GLOBAL] cursor_name } | cursor_variable_name}
] }
[OPTION (<query_hint> [,…n] )]
Transact-SQL的UPDATE语句不支持依赖SELECT语句的更新操作。如果你的Oracle程序这样做了,你可以把SELECT语句变成一个视图,然后在SQL Server的UPDATE语句中使用这个视图名字。请参看前面“INSERT”语句中的例子。
Oracle的UPDATE命令只能使用一个PL/SQL块中的程序变量。Transact-SQL语言不要求在使用变量时使用块。
Oracle
Microsoft SQL
DECLARE
VAR1 NUMBER(10,2);
BEGIN
VAR1 := 2500;
UPDATE STUDENT_ADMIN.STUDENT
SET TUITION_TOTAL = VAR1;
END;
DECLARE
@VAR1 NUMERIC(10,2)
SELECT @VAR1 = 2500
UPDATE STUDENT_ADMIN.STUDENT
SET TUITION_TOTAL=@VAR1