本部分简要介绍了Transact-SQL和PL/SQL语言语法上的相似和不同之处,并且给出了转换策略。 SELECT和数据操作声明 当你把Oracle DML语句和PL/SQL程序移植到SQL Server上时,请按下列步骤进行: 1. 检查所有SELECT、INSERT、UPDATE、和DELETE语句是否有效。做任何需要的修改。 2. 把所有的外部节点改为SQL-92外部节点语法 3. 用适当的SQL Server函数代替Oracle函数 4. 检查所有的比较操作符 5. 用“+”代替“||”做字符串串联操作符。 6. 用Transact-SQL程序代替PL/SQL程序 7. 把所有的PL/SQL游标改为无游标SELECT语句或者Transact-SQL游标。 8. 用Transact-SQL过程代替PL/SQL过程、函数和封装。 9. 把PL/SQL触发器转换为Transact-SQL触发器。 10. 使用SET SHOWPLAN语句来调试你的查询以获得高的性能。 SELECT statements语句 Oracle和Microsoft SQL Server用的SELECT语句的语法是类似的。 Oracle Microsoft SQ
SELECT [/*+ optimizer_hints*/] SELECT select_list In addition: UNION Operator 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 SQ
SELECT CCODE, CNAME SELECT CCODE, CNAME 下例使用MINUS操作符来找出那些没有学生的班级。 Oracle Microsoft SQ
SELECT CCODE, CNAME SELECT CCODE, CNAME INSERT语句 Oracle和Microsoft SQL Server用的INSERT语句的语法是类似的。 Oracle Microsoft SQ
INSERT INTO INSERT [INTO]
Transact-SQL语言支持插入表和视图,但是不支持SELECT语句中的INSERT操作。如果你的Oracle程序这么做了,则必须修改。 Oracle Microsoft SQ
INSERT INTO (SELECT SSN, CCODE,
GRADE FROM GRADE) INSERT INTO GRADE (SSN,
CCODE, GRADE) 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 SQ
UPDATE UPDATE Transact-SQL的UPDATE语句不支持依赖SELECT语句的更新操作。如果你的Oracle程序这样做了,你可以把SELECT语句变成一个视图,然后在SQL
Server的UPDATE语句中使用这个视图名字。请参看前面“INSERT”语句中的例子。 Oracle的UPDATE命令只能使用一个PL/SQL块中的程序变量。Transact-SQL语言不要求在使用变量时使用块。 Oracle Microsoft SQ
DECLARE DECLARE 在SQL
Server中,关键字DEFAULT可以用来把一列设置为它的缺省值。你不能用Oracle的UPDATE命令来设置一列为它的缺省值。 Transact-SQL和Oracle
SQL都支持在一个UPDATE语句中使用子查询。但是Transact-SQL的FROM子句可以用来创建一个基于节点的UPDATE。这个能力是你的UPDATE语法更加可读并且在某种意义上提高了性能。 Oracle Microsoft SQ
UPDATE
Subquery: UPDATE
FROM clause: UPDATE
DELETE语句 在大多数情况下,你不需要修改DELETE语句。但是如果你在Oracle中执行依赖SELECT语句的删除操作,你就必须进行修改,因为在Transact-SQL不支持这种功能。 Transact-SQL支持在WHERE子句中使用子查询,FROM子句也一样。后者可以产生更有效的语句。请参看前面在“UPDATE语句”中的例子。 Oracle Microsoft SQ
DELETE [FROM] DELETE [WHERE TRUNCATE TABLE语句 在Oracle和Microsoft SQL Server中TRUNCATE TABLE语句的语法是相似的。TRUNCATE
TABLE语句用来把一个表中的所有行清除掉,并且这个操作是不能后滚的。该表的结构和索引仍然存在。DELETE触发器不会被执行。如果该表被一个FOREIGN
KEY引用,则该表不能被砍掉。 Oracle Microsoft SQ
TRUNCATE TABLE table_name TRUNCATE TABLE
table_name 在SQL Server中,这个语句只能由表的所有者给出。在Oracle中,只有当你是表的所有者或者有DELETE
TABLE系统特权时才能使用该语句。 Oracle的TRUNCATE TABLE命令可以随意的释放被表中的行占据的存储空间。SQL Server的 TRUNCATE
TABLE则总是回收被表中的数据和与之关联的索引占据的空间。 在identity和timestamp列中操作数据 Oracle序列是一种和任何给定的表或者列都不直接相关的数据库对象。一列和一个序列的关系是在应用程序中实现的,方法是把一个序列的值分配给一个列。因此在同序列一起工作的时候,Oracle并没有强化任何规则。但是在Microsoft
SQL Server的标识列中,值是不能被更新的并且也不能使用DEFAULT关键字。 缺省情况下,数据不能直接插入到一个标识列中。标识列为新插入表的每一行自动产生一个唯一的、顺序的数字。这个缺省设置可以用下面的SET语句覆盖。 SET IDENTITY_INSERT table_name
ON 当IDENTITY_INSERT设置为ON时,用户就可以在新行的标识列中插入任何值。为了防止输入重复的值,必须在该列上创建一个唯一的索引。这个语句的目的是允许用户为一行重新创建一个偶然被删除的值。@@IDENTITY可以用来获取最后一个标识值。 TRUNCATE
TABLE语句把一个标识列重新设置为它原来的SEED值。如果你不想为一列重新设置标识值,可以用不带WHERE子句的DELETE子句来代替TRUNCATE
TABLE语句。你必须估计这会给你的Oracle移植带来什么样的影响,因为ORACLE SEQUENCES不会跟着TRUNCATE
TABLE命令重新设置。 对时间信息(timestamp)列,你只能执行插入或者删除操作。如果你试图更新一个时间信息列,你将收到这样的错误消息。 Msg 272, Level 16, State 1 Can't update
a TIMESTAMP column. 锁定被请求的行 Oracle用FOR UPDATE子句来锁定在SELECT命令中指定的行。在Microsoft SQL
Server中,你不需要使用它的等价子句,因为这是一个缺省行为。 行合计和计算子句 SQL
Server的COMPUTE子句用来生成行合计函数(SUM、AVG、MIN、MAX、以及COUNT),这些函数看起来好象是查询结果的附加行。这允许你看到一组结果的详情和汇总。你可以为一个子群(subgroups)计算汇总值,还可以为同一组计算更多的合计函数。 Oracle的SELECT命令语法不支持COMPUTE子句。但是,SQL
Server的COMPUTE子句就像在Oracle的SQL*Plus查询工具中能找到的COMPUTE命令一样的工作。 连接子句(Join clauses) Microsoft SQL Server
7.0允许在一个连接子句中连接多达256个表,包括临时的和永久的表。在Oracle中,没有连接限制。 在Oracle中使用外部连接时,外部连接操作符(+)典型的放置在子列(foreign
key)的后面。(+)依靠少数几个唯一值来识别该列。除非子列允许空值,否则总是这样的。如果子列允许空值,则(+)被放置在父列(PRIMARY
KEY或者UNIQUE约束)上。你不能把(+)同时放在等号(=)的两边。 用SQL
Server,你可以使用(*=)和(=*)外部连接操作符。(*)用来标识一个有很多唯一值的列。如果子列不允许空值,则(*)被放在等号的父列一边。在Oracle中,(*)的放置正好相反。不能把(*)同时放在等号的两边。 (*=)和(=*)被认为是传统的连接操作符。SQL
Server也支持下面列出的SQL-92标准的连接操作符。建议你使用这种语法。SQL-92标准语法比(*)操作符更强大,限制更小。 Join操作 描述 CROSS JOIN 这是两个表的交叉产物。如果在一个旧式的连接中没有指定WHERE子句,则返回同一行。在Oracle中,这种类型的连接叫做笛卡儿连接。 INNER 该连接指定返回所有的内部行。任何不匹配的行将被丢弃。该连接同一个标准的Oracle表连接是一样的。 LEFT[OUTER] 这种类型的连接指定返回右边表的所有外部行,即使没有发现任何匹配行。该操作符同Oracle外部连接(+)是一样的。 RIGHT[OUTER] 这种类型的连接指定返回左边表的所有外部行,即使没有发现任何匹配行。该操作符同Oracle外部连接(+)是一样的。 FULL [OUTER] 如果来自任一表的一行不匹配选择标准,指定该行被包括到结果集中,并且它的符合其它表的输出列被设定为NULL。这和把Oracle外部连接操作符放在“=”的两端是一样的(col1(+)
= col2(+)),而在Oracle中,这是不允许的。 下面的例子返回所有学生都要上的课程的一个清单。在学生表和年级表之间定义的外部连接允许显示所有的学生,甚至那些没有参加任何课程的学生。在课程表上也有一个外部连接,该连接返回课程名字。如果课程表上没有加上外部连接,则不会返回那些没有参加任何课程的学生,因为他们的课程代码(CCDOE)是空值。 Oracle Microsoft SQServer
SELECT S.SSN AS SSN, SELECT S.SSN AS SSN, 用SELECT语句做表名 Microsoft SQL Server和Oracle都支持在执行查询时用SELECT语句作为表源。SQL
Server需要一个别名(alias);而在Oracle中是否使用别名是可选的。 Oracle Microsoft SQ
SELECT SSN, LNAME,
FNAME, SELECT SSN, LNAME,
FNAME, 读取和修改BLOBs Microsoft SQL Server用text和image列来实现二进制大对象(binary large
objects,BLOBs)。Oracle则用LONG和LONG
RAW列来实现BLOBs。在Oracle中,SELECT命令可以查询LONG和LONG RAW列的值。 在SQL
Server中,你可以使用标准的Transact-SQL语句或者专门的READTEXT语句来读取text和image列中的数据。READTEXT语句允许你读取text和image列的一部分。Oracle没有为LONG
和LONG RAW提供等价的语句。 READTEXT语句利用了一个text_pointer,该指针可以用TEXTPTR函数获取。TEXTPTR函数返回一个指向特定行中的text或者image的指针,如果查询有多于一行返回的话,则返回指向最后一行中的text或者image的指针。由于TEXTPTR返回的是一个16字节的二进制字符串,所以最好是声明一个内部变量来保持该文本指针,然后在READTEXT中使用这个变量。 READTEXT语句说明了有几个字节要返回。位于@@TEXTSIZE函数中的值,限制了返回的字符或者字节的数量,如果该值小于READTEXT声明的值,就用后者来代替。 SET语句可以用TEXTSIZE参数来说明以字节为单位的由一个SELECT语句返回的文本数据的尺寸。如果你设置一个大小为0的TEXTSIZE,则该尺寸就重设为缺省值(4
KB)。设置TEXTSIZE对@@TEXTSIZE函数有影响。当SQL_MAX_LENGTH 语句选项改变的时候,SQL Server
ODBC自动设置TEXTSIZE参数。 在Oracle中,用UPDATE和INSERT命令来改变LONG和LONG RAW列中的值。在SQL
Server,你可以用标准的UPDATE和INSERT语句,或者也可以用UPDATETEXT和WRITETEXT语句。UPDATETEXT和WRITETEXT都允许一个nonlogged选项,而且UPDATETEXT还允许对文本或者图形列的部分更新。 UPDATETEXT可以用来代替已有的数据,删除已有的数据,或者插入新数据。新插入的数据可以是一个常数值,表名,列名或者文本指针。 WRITETEXT语句完全覆盖它所影响的列中的任何已有的数据。用WRITETEXT来替换文本数据,用UPDATETEXT来修改文本数据。因为UPDATETEXT语句只修改一个文本或者图形值的一部分而不是全部的值,所以UPDATETEXT语句更灵活一些。 欲了解详细信息,请参阅SQL Server联机手册。 函数 本节中的表显示了Oracle和SQL Server
的scalar-valued和合计函数之间的关系。尽管名字是一样的,很重要的一点是注意到函数参数的个数和类型之间的区别。那些只有Microsoft
SQL
Server提供的函数在这个清单中没有提及,因为本章限制在使现存的Oracle应用程序的移植工作更容易。例如,这些函数不被Oracle支持:角度(DEGREES),PI(PI),和随机数(RAND) 数字/数学函数 下面是Oracle支持的数字/数学函数以及它们的Microsoft SQL Server等价函数。 函数 Oracle Microsoft SQServer
绝对值 ABS ABS Arc cosine ACOS ACOS Arc sine ASIN ASIN Arc tangent of n ATAN ATAN Arc tangent of n and m ATAN2 ATN2 Smallest integer >=
value CEIL CEILING Cosine COS COS Hyperbolic cosine COSH COT Exponential value EXP EXP Largest integer <= value
FLOOR FLOOR Natural logarithm LN LOG Logarithm, any base LOG(N) N/A Logarithm, base 10 LOG(10) LOG10 Modulus (remainder) MOD USE MODULO (%) OPERATOR
Power POWER POWER Random number N/A RAND Round ROUND ROUND Sign of number SIGN SIGN Sine SIN SIN Hyperbolic sine SINH N/A Square root SQRT SQRT Tangent TAN TAN Hyperbolic tangent TANH N/A Truncate TRUNC N/A Largest number in list GREATEST N/A Smallest number in list LEAST N/A Convert number if NULL NVL ISNULL 字符函数 下面是Oracle支持的字符函数和它们的Microsoft SQL Server等价函数。 函数 Oracle Microsoft SQServer 把字符转换为ASCII ASCII ASCII 字串连接 CONCAT (expression + expression) 把ASCII转换为字符 CHR CHAR 返回字符串中的开始字符(左起) INSTR CHARINDEX 把字符转换为小写 LOWER LOWER 把字符转换为大写 UPPER UPPER 填充字符串的左边 LPAD N/A 清除开始的空白 LTRIM LTRIM 清除尾部的空白 RTRIM RTRIM 字符串中的起始模式(pattern) INSTR PATINDEX 多次重复字符串 RPAD REPLICATE 字符串的语音表示 SOUNDEX SOUNDEX 重复空格的字串 RPAD SPACE 从数字数据转换为字符数据 TO_CHAR STR 子串 SUBSTR SUBSTRING 替换字符 REPLACE STUFF 将字串中的每个词首字母大写 INITCAP N/A 翻译字符串 TRANSLATE N/A 字符串长度 LENGTH DATELENGTH or LEN 列表中最大的字符串 GREATEST N/A 列表中最小的字符串 LEAST N/A 如果为NULL则转换字串 NVL ISNULL 日期函数 下面是Oracle支持的日期函数和它们的Microsoft SQL Server等价函数。 函数 Oracle Microsoft SQServer 日期相加 (date column +/- value) or DATEADD 两个日期的差 (date column +/- value) or DATEDIFF 当前日期和时间 SYSDATE GETDATE() 一个月的最后一天 LAST_DAY N/A 时区转换 NEW_TIME N/A 日期后的第一个周日 NEXT_DAY N/A 代表日期的字符串 TO_CHAR DATENAME 代表日期的整数 TO_NUMBER DATEPART 日期舍入 ROUND CONVERT 日期截断 TRUNC CONVERT 字符串转换为日期 TO_DATE CONVERT 如果为NULL则转换日期 NVL ISNULL 转换函数 下面是Oracle支持的转换函数和它们的Microsoft SQL Server等价函数。 函数 Oracle Microsoft SQServer 数字转换为字符 TO_CHAR CONVERT 字符转换为数字 TO_NUMBER CONVERT 日期转换为字符 TO_CHAR CONVERT 字符转换为日期 TO_DATE CONVERT 16进制转换为2进制 HEX_TO_RAW CONVERT 2进制转换为16进制 RAW_TO_HEX CONVERT |