首页  编辑  

SQL语言支持


SQL语言支持

本部分简要介绍了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*/]
[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 SQ

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 SQ

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 SQ

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 SQ

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 SQ

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 SQ

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

在SQL Server中,关键字DEFAULT可以用来把一列设置为它的缺省值。你不能用Oracle的UPDATE命令来设置一列为它的缺省值。

Transact-SQL和Oracle SQL都支持在一个UPDATE语句中使用子查询。但是Transact-SQL的FROM子句可以用来创建一个基于节点的UPDATE。这个能力是你的UPDATE语法更加可读并且在某种意义上提高了性能。

Oracle

Microsoft SQ

UPDATE
   STUDENT_ADMIN.STUDENT S
SET TUITION_TOTAL = 1500
WHERE SSN IN (SELECT SSN
FROM GRADE G
WHERE G.SSN = S.SSN
AND G.CCODE = '1234')

Subquery:

UPDATE
   STUDENT_ADMIN.STUDENT S
SET TUITION_TOTAL = 1500
WHERE SSN IN (SELECT SSN
FROM GRADE G
WHERE G.SSN = S.SSN
AND G.CCODE = '1234')

FROM clause:

UPDATE
   STUDENT_ADMIN.STUDENT S
SET TUITION_TOTAL = 1500
   FROM GRADE G
      WHERE S.SSN = G.SSN
      AND G.CCODE = '1234'

DELETE语句

在大多数情况下,你不需要修改DELETE语句。但是如果你在Oracle中执行依赖SELECT语句的删除操作,你就必须进行修改,因为在Transact-SQL不支持这种功能。

Transact-SQL支持在WHERE子句中使用子查询,FROM子句也一样。后者可以产生更有效的语句。请参看前面在“UPDATE语句”中的例子。

Oracle

Microsoft SQ

DELETE [FROM]
{table_name | view_name |    select_statement}
[WHERE clause]

DELETE
[FROM ]
{
table_name [ [AS] table_alias] WITH ( <table_hint_limited> […n])
| view_name [ [AS] table_alias]
| rowset_function_limited
}

[ FROM {<table_source>} [,…n] ]

[WHERE
{ <search_condition>
|    { [ CURRENT OF
{
{ [ GLOBAL ] cursor_name }
cursor_variable_name
}
]
}
]
[OPTION (<query_hint> [,…n])]

TRUNCATE TABLE语句

在Oracle和Microsoft SQL Server中TRUNCATE TABLE语句的语法是相似的。TRUNCATE TABLE语句用来把一个表中的所有行清除掉,并且这个操作是不能后滚的。该表的结构和索引仍然存在。DELETE触发器不会被执行。如果该表被一个FOREIGN KEY引用,则该表不能被砍掉。

Oracle

Microsoft SQ

TRUNCATE TABLE table_name
[{DROP | REUSE} STORAGE]

TRUNCATE TABLE table_name

在SQL Server中,这个语句只能由表的所有者给出。在Oracle中,只有当你是表的所有者或者有DELETE TABLE系统特权时才能使用该语句。

Oracle的TRUNCATE TABLE命令可以随意的释放被表中的行占据的存储空间。SQL Server的 TRUNCATE TABLE则总是回收被表中的数据和与之关联的索引占据的空间。

identitytimestamp列中操作数据

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,
FNAME, LNAME
FROM STUDENT_ADMIN.STUDENT S,
DEPT_ADMIN.CLASS C,
STUDENT_ADMIN.GRADE G
WHERE S.SSN = G.SSN(+)
AND G.CCODE = C.CCODE(+)

SELECT S.SSN AS SSN,
FNAME, LNAME
FROM STUDENT_ADMIN.GRADE G
RIGHT OUTER JOIN
STUDENT_ADMIN.STUDENT S
ON G.SSN = S.SSN
LEFT OUTER JOIN
DEPT_ADMIN.CLASS C
ON G.CCODE = C.CCODE

SELECT语句做表名

Microsoft SQL Server和Oracle都支持在执行查询时用SELECT语句作为表源。SQL Server需要一个别名(alias);而在Oracle中是否使用别名是可选的。

Oracle

Microsoft SQ

SELECT SSN, LNAME, FNAME,
TUITION_PAID, SUM_PAID
FROM STUDENT_ADMIN.STUDENT,
(SELECT SUM(TUITION_PAID) SUM_PAID FROM    STUDENT_ADMIN.STUDENT)

SELECT SSN, LNAME, FNAME,
TUITION_PAID, SUM_PAID
FROM STUDENT_ADMIN.STUDENT,
(SELECT SUM(TUITION_PAID) SUM_PAID FROM    STUDENT_ADMIN.STUDENT) SUM_STUDENT

读取和修改BLOBs

Microsoft SQL Server用textimage列来实现二进制大对象(binary large objects,BLOBs)。Oracle则用LONG和LONG RAW列来实现BLOBs。在Oracle中,SELECT命令可以查询LONG和LONG RAW列的值。

在SQL Server中,你可以使用标准的Transact-SQL语句或者专门的READTEXT语句来读取textimage列中的数据。READTEXT语句允许你读取textimage列的一部分。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
ADD_MONTHS

DATEADD

两个日期的差

(date column +/- value) or
MONTHS_BETWEEN

DATEDIFF

当前日期和时间

SYSDATE

GETDATE()

一个月的最后一天

LAST_DAY

N/A

时区转换

NEW_TIME

N/A

日期后的第一个周日

NEXT_DAY

N/A

代表日期的字符串

TO_CHAR

DATENAME

代表日期的整数

TO_NUMBER
(TO_CHAR))

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