Oracle和SQL Server的语法区别.docx
《Oracle和SQL Server的语法区别.docx》由会员分享,可在线阅读,更多相关《Oracle和SQL Server的语法区别.docx(77页珍藏版)》请在冰豆网上搜索。
![Oracle和SQL Server的语法区别.docx](https://file1.bdocx.com/fileroot1/2023-8/4/470846cf-9fc4-4e74-983d-51fe1a8e8fe1/470846cf-9fc4-4e74-983d-51fe1a8e8fe11.gif)
Oracle和SQLServer的语法区别
SQL语言支持
这一部分概述了Transact-SQL和PL/SQL语言语法之间的相同点和不同点,并给出转换策略。
要将OracleDML语句和PL/SQL程序迁移到SQLServer时,请按下列步骤执行:
1.验证所有SELECT、INSERT、UPDATE和DELETE语句的语法是有效的。
进行任何必要的修改。
2.把所有外部联接改为SQL-92标准外部联接语法。
3.用相应SQLServer函数替代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.使用SETSHOWPLAN语句,优化查询性能。
SELECT语句
Oracle和MicrosoftSQLServer使用的SELECT语句语法类似。
Oracle
MicrosoftSQLServer
SELECT[/*+optimizer_hints*/]
[ALL|DISTINCT]select_list
[FROM
{table_name|view_name|select_statement}]
[WHEREclause]
[GROUPBYgroup_by_expression]
[HAVINGsearch_condition]
[STARTWITHUCONNECTBY]
[{UNION|UNIONALL|INTERSECT|
MINUS}SELECTU]
[ORDERBYclause]
[FORUPDATE]
SELECTselect_list
[INTOnew_table_]
FROMtable_source
[WHEREsearch_condition]
[GROUPBY[ALL]group_by_expression[,Un]
[WITH{CUBE|ROLLUP}]
[HAVINGsearch_condition]
[ORDERBYorder_expression[ASC|DESC]]
Inaddition:
UNIONOperator
COMPUTEClause
FORBROWSEClause
OPTIONClause
SQLServer不支持Oracle特定的基于开销的优化程序提示,它必须被删除。
建议使用的技术是,使用SQLServer基于开销的优化程序。
有关详细信息,请参见本章后面的“SQL语句优化”。
SQLServer不支持Oracle的STARTWITHUCONNECTBY子句。
在SQLServer中,可以创建完成相同任务的存储过程替代它。
SQLServer不支持Oracle的INTERSECT和MINUS集合运算符。
可使用SQLServerEXISTS和NOTEXISTS子句,实现相同的结果。
在下面示例中,使用INTERSECT运算符,用于查找学生登记的所有课程的代码和名称。
注意,EXISTS运算符是如何代替INTERSECT运算符的。
返回的数据是相同的。
Oracle
MicrosoftSQLServer
SELECTCCODE,CNAME
FROMDEPT_ADMIN.CLASS
INTERSECT
SELECTC.CCODE,C.CNAME
FROMSTUDENT_ADMIN.GRADEG,
DEPT_ADMIN.CLASSC
WHEREC.CCODE=G.CCODE
SELECTCCODE,CNAME
FROMDEPT_ADMIN.CLASSC
WHEREEXISTS
(SELECT'X'FROMSTUDENT_ADMIN.GRADEG
WHEREC.CCODE=G.CCODE)
在此例中,使用MINUS运算符,查找那些没有任何学生登记的课程。
Oracle
MicrosoftSQLServer
SELECTCCODE,CNAME
FROMDEPT_ADMIN.CLASS
MINUS
SELECTC.CCODE,C.CNAME
FROMSTUDENT_ADMIN.GRADEG,
DEPT_ADMIN.CLASSC
WHEREC.CCODE=G.CCODE
SELECTCCODE,CNAME
FROMDEPT_ADMIN.CLASSC
WHERENOTEXISTS
(SELECT'X'FROMSTUDENT_ADMIN.GRADEG
WHEREC.CCODE=G.CCODE)
INSERT语句
Oracle和MicrosoftSQLServer使用的INSERT语句语法类似。
Oracle
MicrosoftSQLServer
INSERTINTO
{table_name|view_name|select_statement}[(column_list)]
{values_list|select_statement}
INSERT[INTO]
{
table_name[[AS]table_alias]WITH([Un])
|view_name[[AS]table_alias]
|rowset_function_limited
}
{[(column_list)]
{VALUES({DEFAULT
|NULL
|expression
}[,Un]
)
|derived_table
|execute_statement
}
}
|DEFAULTVALUES
Transact-SQL语言支持对表和视图的插入,但不支持对SELECT语句的INSERT操作。
如果Oracle应用程序代码执行对SELECT语句的插入操作,则必须对它进行修改。
Oracle
MicrosoftSQLServer
INSERTINTO(SELECTSSN,CCODE,GRADEFROMGRADE)
VALUES('111111111','1111',NULL)
INSERTINTOGRADE(SSN,CCODE,GRADE)
VALUES('111111111','1111',NULL)
Transact-SQLvalues_list参数提供了SQL-92标准关键字DEFAULT,但Oracle不支持。
此关键字指定了,执行插入操作时使用列的默认值。
如果指定列的默认值不存在,则插入NULL。
如果该列不允许NULL,则返回一个错误消息。
如果该列数据类型定义为timestamp,则插入下一个有序值。
标识符列不能使用DEFAULT关键字。
要生成下一个序列号,拥有IDENTITY属性的列不能列在column_list或values_clause中。
不需使用DEFAULT关键字,来获取列的默认值。
正如在Oracle中,如果列没有在column_list中引用,并且它有默认值,则默认值存放在列中。
这是迁移时可使用的最兼容的方法。
一个有用的Transact_SQL选项(EXECuteprocedure_name)是,执行一个过程并将其结果用管道输出到目标表或视图中。
Oracle不允许这样做。
UPDATE语句
因为TransactSQL支持OracleUPDATE命令使用的绝大多数语法,所以只需要极少的修改。
Oracle
MicrosoftSQLServer
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([Un])
view_name[[AS]table_alias]
|rowset_function_limited
}
SET
{column_name={expression|DEFAULT|NULL}
|@variable=expression
|@variable=column=expression}[,Un]
{{[FROM{}[,Un]]
[WHERE
]}
|
[WHERECURRENTOF
{{[GLOBAL]cursor_name}|cursor_variable_name}
]}
[OPTION([,Un])]
Transact-SQLUPDATE语句不支持对SELECT语句的更新操作。
如果Oracle应用程序代码对SELECT语句进行更新,则可以把SELECT语句转换成一个视图,然后在SQLServerUPDATE语句中使用该视图名称。
请参见前面“INSERT语句”中的示例。
OracleUPDATE命令只能使用一个PL/SQL块中的程序变量。
要使用变量,Transact-SQL语言并不需要使用块。
Oracle
MicrosoftSQLServer
DECLARE
VAR1NUMBER(10,2);
BEGIN
VAR1:
=2500;
UPDATESTUDENT_ADMIN.STUDENT
SETTUITION_TOTAL=VAR1;
END;
DECLARE
@VAR1NUMERIC(10,2)
SELECT@VAR1=2500
UPDATESTUDENT_ADMIN.STUDENT
SETTUITION_TOTAL=@VAR1
在SQLServer中,DEFAULT关键字可用于将一列设为其默认值。
但不能使用OracleUPDATE命令,将一列设为默认值。
Transact-SQL和OracleSQL均支持在UPDATE语句中使用子查询。
但是,Transact-SQLFROM子句可用来创建一个基于联接的UPDATE。
这一功能使UPDATE语法可读性更好,在某些情况下还能改善性能。
Oracle
MicrosoftSQLServer
UPDATE
STUDENT_ADMIN.STUDENTS
SETTUITION_TOTAL=1500
WHERESSNIN(SELECTSSN
FROMGRADEG
WHEREG.SSN=S.SSN
ANDG.CCODE='1234')
Subquery:
UPDATE
STUDENT_ADMIN.STUDENTS
SETTUITION_TOTAL=1500
WHERESSNIN(SELECTSSN
FROMGRADEG
WHEREG.SSN=S.SSN
ANDG.CCODE='1234')
FROMclause:
UPDATE
STUDENT_ADMIN.STUDENTS
SETTUITION_TOTAL=1500
FROMGRADEG
WHERES.SSN=G.SSN
ANDG.CCODE='1234'
DELETE语句
在大多数情况下,不需要修改DELETE语句。
如果要对Oracle中的SELECT语句执行删除操作,则必须修改SQLServer语法,因为Transact-SQL不支持这一功能。
Transact-SQL支持在WHERE子句中使用子查询,以及在FROM子句中使用联接。
后者可产生更有效的语句。
请参见前面“UPDATE语句”中的示例。
Oracle
MicrosoftSQLServer
DELETE[FROM]
{table_name|view_name|select_statement}
[WHEREclause]
DELETE
[FROM]
{
table_name[[AS]table_alias]WITH([Un])
|view_name[[AS]table_alias]
|rowset_function_limited
}
[FROM{}[,Un]]
[WHERE
{
|{[CURRENTOF
{
{[GLOBAL]cursor_name}
cursor_variable_name
}
]
}
]
[OPTION([,Un])]
TRUNCATETABLE语句
Oracle和MicrosoftSQLServer使用的TRUNCATETABLE语句语法类似。
TRUNCATETABLE用于从表中删除所有的行,并且不能回滚。
表结构及其所有索引继续存在。
DELETE触发器不执行。
如果表被一个FOREIGNKEY约束引用,则它不能被截断。
Oracle
MicrosoftSQLServer
TRUNCATETABLEtable_name
[{DROP|REUSE}STORAGE]
TRUNCATETABLEtable_name
在SQLServer中,此语句只能由表的所有者执行。
在Oracle中,如果是表的所有者或拥有DELETETABLE系统权限,就可以执行此命令。
OracleTRUNCATETABLE命令可以有选择地释放表中行所占用的存储空间。
SQLServerTRUNCATETABLE语句总是收回表数据及其相关索引所占用的空间。
标识符列和时间戳列中数据的处理
Oracle序列是与任何给定的表或列均不直接相关的数据库对象。
列和序列之间的关系是在应用程序中实现的,即通过编程的方法将序列值赋给列。
因此,Oracle使用序列时,并不实施任何规则。
但是,在MicrosoftSQLServer标识符列中,值不能被更新,并且不能使用DEFAULT关键字。
默认情况下,数据不能直接插入到标识符列。
标识符列自动给表中插入的每个新行生成一个唯一的序列号。
可以使用下列SET语句改写这种默认设置:
SETIDENTITY_INSERTtable_nameON
将IDENTUTY_INSERT设为ON,用户就可以向新行的标识符列插入任何值。
要防止出现有重复号码的条目,必须为该列创建唯一索引。
这条语句的目的是,允许用户给无意中删除的行重新创建一个值。
@@IDENTITY函数可用来获取上一个标识值。
TRUNCATETABLE语句将标识符列重置为其起始SEED值。
如果不想重置列的标识值,则不使用TRUNCATETABLE语句,而使用不带WHERE子句的DELETE语句。
必须评估它对Oracle迁移造成的影响,因为ORACLESEQUENCE在TRUNCATETABLE命令之后不被重置。
处理timestamp列时,只能执行插入和删除。
如果要更新一个timestamp列,会收到以下的错误信息:
Msg272,Level16,State1Can'tupdateaTIMESTAMPcolumn.
锁定请求的行
Oracle使用FORUPDATE子句来锁定SELECT命令中指定的行。
不需要在MicrosoftSQLServer中使用对等的子句,因为这是默认行为。
行合计和COMPUTE子句
SQLServerCOMPUTE子句用于生成行合计函数(SUM、AVG、MIN、MAX和COUNT),它们在查询结果中作为附加行出现。
它允许查看一组结果的详细和汇总信息行。
可以计算子组的汇总值,以及计算同一组的多个合计函数。
OracleSELECT命令语法不支持COMPUTE子句。
但是,SQLServerCOMPUTE子句与OracleSQL*Plus查询工具中的COMPUTE命令作用相似。
联接子句
MicrosoftSQLServer7.0允许在一个联接子句中最多可联接256个表,包括临时表和永久表。
在Oracle中,则没有联接限制。
在Oracle中使用外部联接时,外部联接运算符(+)通常放在该联接的子列(外键)旁边。
(+)标识了具有较少唯一值的列。
情况一般是这样,除非外键允许空值,在这种情况下,(+)被放在父(PRIMARYKEY或UNIQUE约束)列上。
(+)不能放在等号(=)两边。
在SQLServer中,可以使用*=和=*外部联接运算符。
*用于标识有较多唯一值的列。
如果子(外键)列不允许空值,则*放在等号的父(PRIMARYKEY或UNIQUE约束)列一边。
*的位置和Oracle完全相反。
*不能放在等号(=)两边。
*=和=*被认为是旧式联接运算符。
SQLServer也支持下面列出的SQL-92标准联接运算符。
建议使用这种语法。
SQL-92标准语法功能更强大,并且比*运算符的限制要少。
联接操作
说明
CROSSJOIN
这是两个表的交叉乘积。
它与旧式联接中未指定WHERE子句而返回的行相同。
在Oracle中,这种类型联接称为笛卡尔联接。
INNER
这种联接指定,所有内部行均要返回。
丢弃任何不匹配的行。
这和标准的Oracle表联接相同。
LEFT[OUTER]
这种类型的联接指定,所有左表的外部行均要返回,即使没找到匹配的列,也就如此。
这和Oracle外部联接(+)的操作类似。
RIGHT[OUTER]
这种类型的联接指定,所有右表的外部行均要返回,即使没找到匹配的列,也是如此。
这和Oracle外部联接(+)的操作类似。
FULL[OUTER]
如果两个表中的一行不符合选择标准,则指定将这一行加到结果集中,并且将其对应于另一表的输出列设为NULL。
这和将Oracle外部联接运算符放在“=”号两边(col1(+)=col2(+))的效果是一样的,但后者在Oracle中是不允许的。
下面的代码示例返回所有学生登记的课程列表。
外部联接定义在学生(student)和成绩(grade)表之间,成绩表允许所有的学生出现在上面,甚至那些没有登记任何课程的学生也是如此。
外部联接也加到课程表上,以返回课程名称。
如果外部联接不加到课程表上,就不会返回那些没有登记任何课程的学生,因为他们的课程代码(CCODE)为空。
Oracle
MicrosoftSQLServer
SELECTS.SSNASSSN,
FNAME,LNAME
FROMSTUDENT_ADMIN.STUDENTS,
DEPT_ADMIN.CLASSC,
STUDENT_ADMIN.GRADEG
WHERES.SSN=G.SSN(+)
ANDG.CCODE=C.CCODE(+)
SELECTS.SSNASSSN,
FNAME,LNAME
FROMSTUDENT_ADMIN.GRADEG
RIGHTOUTERJOIN
STUDENT_ADMIN.STUDENTS
ONG.SSN=S.SSN
LEFTOUTERJOIN
DEPT_ADMIN.CLASSC
ONG.CCODE=C.CCODE
将SELECT语句做为表名使用
MicrosoftSQLServer和Oracle均支持在执行查询时,把SELECT语句作为表的来源使用。
SQLServer需要一个别名;对Oracle,别名的使用是可选的。
Oracle
MicrosoftSQLServer
SELECTSSN,LNAME,FNAME,
TUITION_PAID,SUM_PAID
FROMSTUDENT_ADMIN.STUDENT,
(SELECTSUM(TUITION_PAID)SUM_PAIDFROMSTUDENT_ADMIN.STUDENT)
SELECTSSN,LNAME,FNAME,
TUITION_PAID,SUM_PAID
FROMSTUDENT_ADMIN.STUDENT,
(SELECTSUM(TUITION_PAID)SUM_PAIDFROMSTUDENT_ADMIN.STUDENT)SUM_STUDENT
读取和修改BLOB
MicrosoftSQLServer使用text和image列,来实现二进制大型对象(BLOB)。
Oracle使用LONG和LONGRAW列实现BLOB。
在Oracle中,SELECT命令可以查询LONG和LONGRAW列中的值。
在SQLServer中,可以使用标准的Transact-SQL语句或专门的READTEXT语句读取text和image列中的数据。
READTEXT语句允许读取text或image列的部分片段。
Oracle没有提供处理LONG和LONGRAW的对等语句。
READTEXT语句使用text_pointer,它可以用TEXTPTR函数获得。
TEXTPTR函数返回一个指针,它指向指定行中的text或image列,或如果返回不止一行,则它指向查询返回的最后一行的text或image列。
因为TEXTPTR函数返回一个16字节的二进制字符串,最好声明一个局部变量来存放文本指针,然后由READTEXT使用该变量。
READTEXT语句指定要返回的字节数。
@@TEXTSIZE函数中的值是要返回的字符或字节数的限度,如果它小于RE