so法兰型号:Oracle 9i与MS SQL Server 2000之比较连载五 - 博客文库 - 博...

来源:百度文库 编辑:中财网 时间:2024/04/29 13:20:23
Oracle 9i与MS SQL Server 2000之比较连载五
中新的数据库对象:
实例化视图、快照、序列、程序包、同义词、抽象的数据类型
●          实例化视图又称显形图:实例化说明它有自己的存储空间,视图说明它的数据来源于其它表数据。实例化视图中的数据,设置为隔一段时间更新数据,更新的模式可以定义为完全更新和增量更新
●          快照基本上同实例化视图,只不过数据来源不同,快照数据来源于远程数据库,而实例化视图则来源于本地数据表
●          序列,相当于MS SQL 中的identity列,它是一个数字顺序列表,下面有详细介绍。
●          程序包,它是过程、函数、全局变量的集合,它封装了私有变量、私有过程和私有函数,如:dbms-out包
●          同义词,是对数据库中的对象的别名,同义词可以是全局的也可以是私有的(属于某个用户的)如:Tab、col等
●          抽象的数据类型,类似于C中的结构体或Pascal记录类型。
回滚段和SQL Server的数据库事务日志文件
回滚段提供了事物回滚需要使用的数据变化以前的映象,这些映象是按条目存储的,如果这些条目过少,一个事务等待另一个事务的几率增大,就会影响数据库的性能。缺省安装时,提供一个系统回滚段,它在system表空间。为了提高性能,system表空间不应存储有任何数据字典信息以外的信息。每次启动时,Oracle RDBMS 执行自动恢复。它检验表空间文件的内容是否与联机重做日志文件一致。如果不一致,Oracle 将联机重做日志文件内容应用到表空间文件(前滚),并删除回滚段中发现的任何未提交的事务(回滚)。如果 Oracle 不能从联机重做日志文件中得到它所需要的信息,它就会查询存档重做日志文件。
每个 SQL Server 事务日志均有 Oracle 回滚段与 Oracle 联机重做日志的组合功能。每个数据库都有自已的事务日志,它记录了对数据库所作的全部更改,并且由数据库的所有用户共享。当一个事务开始且发生数据修改时,就会在日志中记录一个 BEGIN TRANSACTION 事件(以及修改事件)。在自动故障恢复过程中,这个事件用于确定事务的起始点。在收到每个数据修改语句时,先将更改写入事务日志,然后再写入数据库。MS SQL 数据库事务日志文件功能雷同于回滚段,只不过它是同特定的数据库密切相关的。

ORACLE的数据类型
常用的数据库字段类型如下:
字段类型
中文说明
限制条件
其它说明
CHAR
固定长度字符串
最大长度2000 bytes
VARCHAR2
可变长度的字符串
最大长度4000 bytes
可做索引的最大长度749
NCHAR
根据字符集而定的固定长度字符串
最大长度2000 bytes
NVARCHAR2
根据字符集而定的可变长度字符串
最大长度4000 bytes
DATE
日期(日-月-年)
DD-MM-YY(HH-MI-SS)

LONG
可变长度的字符数据
最大长度2G(231-1)
足够存储大部头著作
RAW
固定长度二进制数据
最大长度2000 bytes
可存放比较小的多媒体图象声音等
LONG RAW
可变长度的二进制数据
最大长度2G
可存放比较大的多媒体图象声音等
BLOB
大型的二进制对象(可变长度)
最大长度4G
1、  一个表可有多个这
种列
2、使用select语句只能返回存储这种数据的位置
3、既可联机存储,也可脱机存储
4、支持对象(Object)类型
5、随机访问数据
CLOB
大型的CHAR类型数据
NCLOB
大型的NCHAR类型数据
BFILE
存放在数据库外的大型的二进制文件
ROWID
数据表中记录的唯一行号
10 bytes ********.****.****格式,*为0或1,存储在索引中。
UROWID
同上
存储在索引中
NROWID
二进制数据表中记录的唯一行号
最大长度4000 bytes
NUMBER(P,S)
数字类型
P为总的位数,S为小数位
DECIMAL(P,S)
数字类型
P为总的位数,S为小数位
INTEGER
整数类型
小的整数
FLOAT
浮点数类型
NUMBER(38),双精度
REAL
实数类型
NUMBER(63),精度更高

注意:每个表中只能有一个LONG或LONG  RAW列,……….。

                                                  
      二者映射关系: From  SQL Server  To  Oracle

SQL Server 2000 数据类型
Oracle 数据类型
bigint
NUMBER
binary
LONG RAW NOT NULL
bit
NUMBER (1, 0)
char
VARCHAR2 (900) NOT NULL
datetime
DATE
decimal
NUMBER (255, 3) NOT NULL
float
FLOAT NOT NULL
image
LONG RAW
int
NUMBER (255, 3) NOT NULL
money
NUMBER (255, 3) NOT NULL
nchar
VARCHAR2 (2000) NOT NULL
ntext
LONG
numeric
NUMBER (255, 3) NOT NULL
nvarchar
VARCHAR2 (2000) NOT NULL
real
FLOAT NOT NULL
smallint
NUMBER (255, 3) NOT NULL
smalldatetime
DATE NOT NULL
smallmoney
NUMBER (255, 3) NOT NULL
sql_variant
LONG
sysname
CHAR(255)
text
LONG
timestamp
RAW (255)
tinyint
NUMBER (255, 3) NOT NULL
From  Oracle  To  SQL Server
Oracle
Microsoft SQL Server
CHAR
建议使用 char。因为 char 类型的列使用固定的存储长度,所以,访问时比 varchar 列要快一些。
VARCHAR2
和 LONG
varchar 或 text。(如果 Oracle 列中数据值的长度为 8000 字节或更少,则使用 varchar;否则,必须使用 text。)
RAW 和
LONG RAW
varbinary 或 image。(如果 Oracle 列中数据值的长度为 8000 字节或更少,则使用 varbinary;否则,必须使用 image。)
NUMBER
如果整数在 1 和 255 之间,使用 tinyint。
如果整数在 -32768 和 32767 之间,使用 smallint。
如果整数在 -2,147,483,648 和 2,147,483,647 之间,则使用 int。
如果需要浮点类型数,使用 numeric(有精度和小数位)。
注意:不要使用 float 或 real,因为可能会产生舍入(Oracle NUMBER 和 SQL Server numeric 均不舍入)。
如果不确定,则使用 numeric;它最接近 Oracle NUMBER 数据类型。
ROWID
使用 identity 列类型。
CURRVAL, NEXTVAL
使用 identity 列类型以及 @@IDENTITY、IDENT_SEED() 和 IDENT_INCR() 函数。
1、基本SQL语句的区别
语句
l         SQL Server 不支持 Oracle 的 INTERSECT 和 MINUS 集合运算符。可使用 SQL Server EXISTS 和 NOT EXISTS 子句,实现相同的结果。
下面两条语句返回的数据是相同的。
Oracle(返回两个查询都有的行)
Microsoft SQL Server
SELECT  CCODE, CNAME
FROM    DEPT
INTERSECT
SELECT  C.CCODE, C.CNAME
FROM   STUDENT  G,
DEPT  C
WHERE  C.CCODE = G.CCODE
SELECT  CCODE, CNAME
FROM    DEPT  C
WHERE  EXISTS
(SELECT  *  FROM
STUDENT  G
WHERE  C.CCODE = G.CCODE)
下面两条语句返回的数据是相同的。
Oracle
Microsoft SQL Server
SELECT  CCODE, CNAME
FROM    DEPT
MINUS
SELECT  C.CCODE, C.CNAME
FROM    STUDENT  G,
DEPT  C
WHERE  C.CCODE = G.CCODE
SELECT    CCODE, CNAME
FROM      DEPT C
WHERE    NOT EXISTS
(SELECT   *  FROM
STUDENT G
WHERE   C.CCODE = G.CCODE)
l       将 SELECT 语句做为表名使用
Microsoft SQL Server 和 Oracle 均支持在执行查询时,把 SELECT 语句作为表的来源使用。SQL Server 需要一个别名;Oracle别名的使用是可选的。
Oracle
Microsoft SQL Server
SELECT   SSN,LNAME,SUM_PAID
FROM     STUDENT,
(SELECT  SUM(TUITION)
SUM_PAID FROM
STUDENT)
SELECT    SSN, LNAME,SUM_PAID
FROM      STUDENT,
(SELECT   SUM(TUITION)
SUM_PAID FROM
STUDENT)   SUM_STUDENT
l        INSERT 语句
T-SQL 语言支持对表和视图的插入,但不支持对 SELECT 语句的 INSERT 操作。如果 Oracle 应用程序代码执行对 SELECT 语句的插入操作,则必须对它进行修改。如:
Oracle
Microsoft SQL Server
INSERT INTO (SELECT SSN, CCODE, GRADE FROM GRADE)
VALUES ('11', '1111',NULL)
INSERT INTO GRADE (SSN, CCODE, GRADE)
VALUES ('11', '1111',NULL)
Transact-SQL values_list 参数提供了 SQL-92 标准关键字 DEFAULT,但 Oracle 不支持。此关键字指定了执行插入操作时使用列的默认值。如果指定列的默认值不存在,则插入 NULL。如果该列不允许 NULL,则返回一个错误消息。如果该列数据类型定义为 timestamp,则插入下一个有序值。
语句
如果要对 Oracle 中的 SELECT 语句执行删除操作,则必须修改 SQL Server 语法,因为 Transact-SQL 不支持这一功能。 Transact-SQL 支持在 WHERE 子句中使用子查询,以及在 FROM 子句中使用联接。后者可产生更有效的语句。请参见后面“UPDATE 语句”中的示例。
Oracle
Microsoft SQL Server
DELETE [FROM]
{table_name | view_name | select_statement}
[WHERE clause]
DELETE
[FROM ]
{
table_name [ [AS] table_alias] WITH ( [Un])
| view_name [ [AS] table_alias]
| rowset_function_limited
}
[ FROM {} [,Un] ]
[WHERE
{
| { [ CURRENT OF
{
{ [ GLOBAL ] cursor_name }
cursor_variable_name
}
]
}
]
[OPTION ( [,Un])]
注意:删除记录并不能释放ORACLE里被占用的数据块表空间. 它只把那些被删除的数据块标成unused.如果确实要删除一个大表里的全部记录, 可以用 TRUNCATE 命令, 它可以释放占用的数据块表空间  TRUNCATE TABLE 表名,但此操作不可回退。
Oracle
Microsoft SQL Server
在SQL*PLUS中不能正确执行这条语句:
BEGIN
IF EXISTS (SELECT * FROM
ONLINEUSER) THEN
DBMS_OUTPUT.PUT_LINE('OK');
END IF;
END;
在查询分析器中能正确地执行这条语句:
IF EXISTS  (SELECT * FROM ONLINEUSER)
PRINT('OK')
注:在Oracle中函数或伪列 'EXISTS' 只能在 SQL 语句中使用 2、表数据复制
MS SQL Server
Insert into  复制表名称  select语句 (复制表已存在)
Select  字段列表  into  复制表名称  from  表(复制表不存在)
Oracle
Insert into 复制表名称 select语句(复制表已存在)
create table 复制表名称 as select语句(复制表不存在)
MS SQL Server
BCP命令行程序
Oracle
SQLLDR命令行程序
3、表数据更新
MS SQL Server
Update   A   SET   字段1=B字段表达式   字段2=B字段表达式
From  B  WHERE  逻辑表达式
如:
UPDATE  titles  SET  ytd_sales =  t.ytd_sales + s.qty
FROM  titles  t, sales  s
WHERE  t.title_id = s.title_id
AND  s.ord_date = (SELECT  MAX(sales.ord_date)  FROM  sales)
Oracle
Update  A  SET  字段1=(select   字段表达式  from  B  WHERE) 字段2=(select  字段表达式  from  B  WHERE)   WHERE 逻辑表达式
假如A需要多个字段更新,显然MS SQL 语句更简练。
l        T-SQL UPDATE 语句不支持对 SELECT 语句的更新操作。
如果 Oracle 应用程序代码对 SELECT 语句进行更新,则可以把 SELECT 语句转换成一个视图,然后在 SQL Server UPDATE 语句中使用该视图名称。请参见前面“INSERT 语句”中的示例。
Oracle  UPDATE 命令只能使用一个 PL/SQL 块中的程序变量。而Transact-SQL 语言并不需要使用块。 如下图:
Oracle
Microsoft SQL Server
DECLARE
VAR1 NUMBER(10,2);
BEGIN
VAR1 := 2500;
UPDATE  STUDENT SET  TUITION = VAR1;
END;
DECLARE
@VAR1 NUMERIC(10,2)
SELECT  @VAR1 = 2500
UPDATE  STUDENT SET  TUITION =@VAR1
在 SQL Server 中,DEFAULT 关键字可用于将一列设为其默认值。但不能使用 Oracle  UPDATE 命令,将一列设为默认值。
Transact-SQL 和 Oracle SQL 均支持在 UPDATE 语句中使用子查询。但是,Transact-SQL FROM 子句可用来创建一个基于联接的 UPDATE。这一功能使 UPDATE 语法可读性更好,在某些情况下还能改善性能。
Oracle
Microsoft SQL Server
UPDATE  STUDENT S SET TUITION = 1500
WHERE  SSN IN (SELECT SSN
FROM GRADE G WHERE G.SSN = S.SSN
AND G.CCODE = '1234')
Subquery:
UPDATE  STUDENT  S  SET  TUITION = 1500
WHERE  SSN  IN  (SELECT SSN
FROM GRADE G WHERE G.SSN = S.SSN
AND G.CCODE = '1234')
FROM clause:
UPDATE  STUDENT  S  SET  TUITION = 1500
FROM  GRADE  G
WHERE S.SSN = G.SSN AND G.CCODE = '1234'
、内联结,外联结, 交叉联接
MS SQL Server
内联接   仅显示两个联接表中的匹配行的联接。(这是查询设计器中的默认联接类型。)例如,可以联接 titles 表和 publishers 表以创建显示每个书名的出版商名称的结果集。在内联接中,结果集内不包含没有出版商信息的书名,也不包含没有书名的出版商。如:
SELECT title, pub_name  FROM  titles INNER JOINpublishers ON titles.pub_id = publishers.pub_id
注意   当创建内联接时,包含 NULL 的列不与任何值匹配,因此不包括在结果集内。空值不与其它的空值匹配。
内联结也就是我们平常的等联结.在SQL-92标准之中,内部联结可指定于FROM或WHERE子句中.这是 SQL-92在WHERE子句中唯一支持的联结类型.
外联接   甚至包括在联接表中没有相关行的行的联接。可以创建外联接的三个变化形式来指定所包括的不匹配行: 左向外联接   包括第一个命名表("左"表,出现在 JOIN 子句的最左边)中的所有行。不包括右表中的不匹配行。例如,下面的 SQL 语句说明 titles 表和 publishers 表之间的左向外联接包括所有的书名,甚至包括那些没有出版商信息的书名:
SELECT titles.title_id, titles.title, publishers.pub_nameFROM titles LEFT OUTER JOIN publishers ON titles.pub_id              = publishers.pub_id右向外联接   包括第二个命名表("右"表,出现在 JOIN 子句的最右边)中的所有行。不包括左表中的不匹配行。例如,在 titles 和 publishers 表之间的右向外联接将包括所有的出版商,甚至包括那些在 titles 表中没有书名的出版商。如:
SELECT titles.title_id, titles.title, publishers.pub_nameFROM titles RIGHT OUTER JOIN publishers ON titles.pub_id              = publishers.pub_id完整外部联接   包括所有联接表中的所有行,不论它们是否匹配。例如,titles 表和 publishers 表之间的完整外部联接显示所有书名和所有出版商,甚至包括那些在另一个表中没有匹配值的书名和出版商。
SELECT titles.title_id, titles.title, publishers.pub_nameFROM titles FULL OUTER JOIN publishers ON titles.pub_id              = publishers.pub_id交叉联接   在这类联接的结果集内,两个表中每两个可能成对的行占一行。例如,在通过作者 CROSS JOIN 出版商输出的结果集内,每个可能的作者/出版商组合占一行。如:
SELECT * FROM authors CROSS JOIN publishers  Oracle(9i以前的版本)
1         字段1=字段2(+)(左连接)
2         字段1(+)=字段2(右连接)
Oracle不支持标准的外连接语法,也没有全外连接。它的外联结与众不同. Oracle的外联结符号是(+),并且在整个select语句中,只能有一张表做为主表和其它的表进行外联.如果你的SQL Server中用到两张或者两张以上的表作为主表的话,那么只有完全改写.并且在SQL Server的外联语句中如果用到了in或者or的话,那转成Oracle将颇费周折.
例程如下:
SQL Server:
select a.COMP_ID,a.TRANS_NO,b.PART_NO from TransMaster a left outer join TransDetail b on (a.COMP_ID = b.COMP_ID and a.TRANS_NO = b.TRANS_NO)
Oracle:
select a.COMP_ID,a.TRANS_NO,b.PART_NO from TransMaster a,TransDetail b
where a.COMP_ID = b.COMP_ID(+) and a.TRANS_NO = b.TRANS_NO(+);
//请注意(+)这个符号应该紧挨着从表的字段出现
Oracle 外连接的一个小技巧: 外部联接"+"按其在"="的左边或右边分左联接和右联接.若不
带"+"运算符的表中的一个行不直接匹配于带"+"预算符的表中的任何行,则前者的行与后者中的
一个空行相匹配并被返回.若二者均不带’+’,则二者中无法匹配的均被返回.利用外部联接"+",可
以替代效率十分低下的 not in 运算,大大提高运行速度.例如,下面这条命令执行起来很慢
Select   a.empno  from  emp  a  where  a.empno   not  in
(select  empno  from  emp1  where  job=’SALE’);
倘若利用外部联接,改写命令如下:
select  a.empno  from  emp a ,emp1 b where  a.empno=b.empno(+)
and  b.empno is null  and  b.job=’SALE’;
可以发现,运行速度明显提高.
Oracle 9i包括以下新的TABLE JOIN的句法结构:
NATURAL  JOIN——这是一个很有用的Oracle 9i的句法,它通过从WHERE子句中移动连接标准来改善SQL的稳定性(相当于SQL Server 内联接,但有区别) LEFT OUTER JOIN——它返回表格中左边的行和右边的数值,如果没有搭配的行的话,则返回零(相当于SQL Server 左向外联接) RIGHT OUTER JOIN——它返回表格中右边的行和左边的数值,如果没有搭配的行的话,则返回零(相当于SQL Server 右向外联接) FULL OUTER JOIN——它返回的是两个表格中所有的行,用零填满每一个空格。这在Oracle8i中则没有相应的此种句法(相当于SQL Server完整外部联接) CROSS  JOIN——它在两个表格中创建了一个卡迪尔列,就象是在Oracle 8i中没写WHERE时那样。(相当于SQL Server交叉联接) USING子句——它可以通过名字来具体指定连接 ON子句——这个句法允许在两个表中为连接具体指定字段的名字, 同SQL Server中的一样。
NATURAL JOIN
我喜欢NATURAL JOIN的原因在于它能够通过在两个表中配对的字段的名字来自动的检查join。它同时还简化了Oracle 9i SQL,当然,NATURAL JOIN要求在每一个表中的字段的名字相同。很有意思的是,这种特性甚至在没有主要的或是外来的关键词作为参考时也能起作用,如下面两条语句功能相同:
Oracle 8i,
Select book_title, sum(quantity)
from book, sales
where book.book_id = sales.book_id
group by book_title;
Oracle 9i
Select book_title, sum(quantity)
from book
natural join sales
group by book_title;
新的OUTER JOIN句法
ISO99标准把复杂的加号从Oracle outer join中拿出去,并使得outer join SQL更容易理解。
LEFT OUTER JOIN
在LEFT OUTER JOIN中,会返回所有左边表格中的行,甚至在被连接的表格中没有可配对的栏目的情况下也如此。在下边的例子中,返回了所有雇员的姓,甚至包括了那些没有分配到部门的雇员。如下面两条语句功能相同:
Oracle8i
select last_name, dept_id
from emp e, dept d
where e.department_id = d.department_id(+);
Oracle9i
select last_name, dept_id
from emp
LEFT OUTER JOIN Dept
ON e.dept_id = d.dept_id;
RIGHT OUTER JOIN
在RIGHT OUTER JOIN中返回的是表格中所有右边的行,甚至在被连接的表格中没有可配对的栏目的情况下也如此。在这个例子中,返回了所有部门的ID,包括那些没有一个雇员的的部门。如下面两条语句功能相同:
Oracle8i
select last_name, d.dept_id
from employees e, departments d
where e.department_id(+) = d.department_id;
Oracle9i
select last_name, d.dept_id
from employees e
RIGHT OUTER JOIN departments d
ON (e.department_id = d.department_id);
CROSS JOIN
在Oracle中,CROSS JOIN产生了一个“卡迪尔的产物(Cartesian product)”,就象是在连接两个表格时忘记加入一个WHERE子句一样
select  last_name, dept_id  from  emp, depts;
在Oracle9i中,我们使用CROSS JOIN 来达到相同的结果
select  last_name, dept_id  from  emp CROSS JOIN dept;
USING子句
假如几个栏目有同样的名字,而你又不想用所有的这些栏目来连接的时候,你就可以用USING子句。在USING子句中所列的栏目的句子中不会有任何的修饰词,包括where子句也不会有, 如下面两条语句功能相同:
Oracle8i
select dept_id, city
from departments, locations
where departments.location_id = location.location_id;
Oracle9i
select dept_id, city
from departments
JOIN locations
USING (location_id);
ON子句
ON子句被用于当在两个表格中的栏目名字不搭配时来连接表格。而连接条件就是where子句中的过滤条件, 如下面两条语句功能相同:
Oracle8i
select department_name, city
from department, location
where department.location_id = location.loc_id;
Oracle9i
select department_name, city
from department d
JOIN location l
ON (d.location_id = l.id);
易变的连接
易变的连接就是两个以上的表格被连接所用的。ISO SQL 1999标准通常假设表格从左至右连接,连接的条件是能够为现在的连接或以前的与左边的连接相关联的栏目提供参考。
Oracle8i
select emp_id, city_name, dept_name from location l, department d, emp e
where d.location_id = l.location_id and d.department_id = e.department_id;
Oracle9i
select emp_id, city_name, dept_name from locations l
JOIN departments d ON (d.location_id = l.location_id)
JOIN employees e ON (d.department_id = e.department_id);
、存储过程或函数中使用的临时表
这是Oracle 明显不如SQL Server的一个地方。
Oracle中的临时表和SQL Server中的临时表根本不是一个概念,它无法达到SQL Server中临
时表的作用,在Oracle的sp中不能create table。
SQL Server的临时表:
SQL Server的临时表有两种: 本地临时表(#)和全局临时表(##) ,二者在名称、可见性和可用性上均不相同。SQL Server的临时表全部都存储在tempdb数据库中,但只要你的tempdb分配了足够大的硬盘空间,在多用户并发操作时临时表的性能就不会降低.并且每隔一段周期SQL SERVER就自动会对tempdb进行碎片整理以确保性能.
本地临时表是独立于每一个用户连接的, 它们仅对当前的用户连接是可见的;当用户从 Microsoft? SQL Server&S482; 2000 实例断开连接时被删除。
全局临时表一旦创建,所有的用户连接都可以使用, 创建后对任何用户都是可见的,当所有引用该表的用户从 SQL Server 断开连接时被删除。
Oracle中的临时表:
Oracle中的临时表和SQL Server中的临时表的处理机制全然不同.Oracle的临时表顶多只能相当于SQL Server中的全局临时表,而且它会永久存在,如果你自己不去drop它的话,Oracle是不会自动将其释放的.而且SQL Server中的局部临时表在Oracle中无法替代,因此我在Oracle中放弃了对临时表的使用,所有的临时表全部改为永久表.
在Oracle的sp中不能出现DDL语句.因为所有的DDL语句(create,drop,alter,truncate等)都是显式带有commit命令,Oracle的sp中不能有显式commit的存在.如果你非要在sp中建表或者删除表的话,你可以用动态SQL来完成隐式commit. 例如: execute immediate “create table ……”; 关于动态SQL,后面将做出详细的介绍.
在这里将有两点要注意,处理不当将影响性能或者导致程序出错:
1. 在sp一开始直接用动态SQL建永久表,然后对表进行操作,sp退出之前再用动态SQL删除永久表.在多用户并发操作的时候。A连接调用了该sp并成功创建了表, B连接也调用该sp试图去创建这张表的时候,Oracle会很野蛮的将sp中断,然后我们的客户就会看到很不友好的出错框.
2. 为了让多用户使用互不干扰,由程序生成sessionid传入sp或者利用Oracle的函数userenv('sessionid’)生成sessionid.然后在sp中用动态SQL生成表名+sessionid的表,对该表进行操作,sp退出时将其删除.
但这样仍会有一个问题:由于sp被经常调用导致不断的建表删表.而Oracle的表都存放在表空间上.这样大量的DDL语句会让表空间内的碎片不断的增多而表空间将不断增大,要知道Oracle的碎片整理必须要手动进行,它不会像SQL SERVER那样自动整理.”Oracle最让人满意的是它可以优化,Oracle最让人不满意的是它必须优化!”过了一个季度甚至于一个月,我们的用户就会向我们抱怨我们的系统跑得越来越慢了.又提到了我前面说过的话:我们的绝大多数程序没有受到真正的考验,如果不考虑清楚的话,我们的系统将有严重的问题.
中的临时表移植到Oracle中我的处理方法如下:
1. 创建CreateTempTable.sql文件,所有原SQL Server中用到的临时表都在此建立,只是每张表多一个字段sessionid int,如果表有主键,那么将sessionid加入主键.
2. 创建DropTempTable.sql文件,里面的内容是:
begin
for r in (select 'drop table '||object_name as sqls from user_objects where
object_type = ' TABLE' and object_name in ('temp1’,’temp2’,……)) loop
//所有的临时表都写在in中
execute immediate (r.sqls);
end loop;
end;
这两个SQL文件让我们的程序自动运行.
3. 由程序生成sessionid或者通过userenv('sessionid’) 生成sessionid写入表的sessionid字段。每个连接只处理本连接的数据。

MS SQL Server
Create  table  ##表名  或 select   into  ##表名
Oracle
CREATE GLOBAL TEMPORARY TABLE temp1
(……
sessionid int)
on commit delete rows;
、group by
下面两条语句执行结果一样:
MS SQL Server  从右往左
select left(catid,1) as "小组号", ISNULL(result,'未评估') as "评估结果",count(*) as "加盟店数量" from cat group by result,left(catid,1)
Oracle         从左往右
select substr(catid,1,1) as "小组号", result as "评估结果",count(*) as "加盟店数量" from cat group by substr(catid,1,1),result
Oracle 的 having 子句对 group by 子句所确定的行组进行控制,having 子句条件中只允许
涉及常量,聚组函数或group by 子句中的列

的sp不能返回结果集。
在Oracle的任何PL/SQL语句块中所有的select语句必须要有into子句! 这就是Oracle的sp不能返回结果集的原因! 本人采用下面的笨办法解决:
create or replace package pkg_test
as
type cur_test is ref cursor; --定义一个cursor的type
end pkg_test;
/
create or replace procedure p_test
(
v_cur out pkg_test.cur_test
)
as
v_sql varchar2(100); --
begin
v_sql := 'select a1,a2 from test';
OPEN v_cur FOR v_sql; --
exception
when others then
DBMS_OUTPUT.PUT_LINE('Error ---------' || sqlcode || ' : ' || sqlerrm );
end p_test;
/
因为所有的DDL语句(create,drop,alter,truncate等)都是显式带有commit命令,Oracle的sp中不能有显式commit的存在。如果你非要在sp中建表或者删除表的话,你可以用动态SQL来完成隐式commit。因此下面的语句在sp中是错误的:
1、Create table 表名
2、Drop table 表名
Microsoft SQL Server 提供了 WAITFOR,它允许开发人员指定触发语句块、存储过程或事务执行的时间、时间间隔或事件。它相当于 Oracle 的 dbms_lock.sleep。
的sp形参需要指定长度(若不指定长度,则系统取默认长度,不一定得到你需要的值),Oracle的sp形参不需要指定长度
下面两条语句执行结果一样:
MS SQL Server:
IF EXISTS (SELECT name
FROM   sysobjects
WHERE  name = N'VALID'
AND   type = 'P')
DROP PROCEDURE VALID
GO
CREATE PROCEDURE VALID
@Yhbh CHAR(6),    --形参需要指定长度
@Password VARCHAR(20),
@Valid bit OUTPUT,
@Invalid  VARCHAR(100) OUTPUT
WITH ENCRYPTION
AS     --所有的局部变量、游标和类型都在这里声明。要用declare。
DECLARE  @V BIT, @I VARCHAR(100)
SELECT @V=valid,@I=invalid FROM MEMBER WHERE  id=@Yhbh AND password=@Password
IF @V=0
BEGIN
SET @Valid=@V     --赋值语句用SET或SELECT
SET @Invalid=@I
END
ELSE
BEGIN
SET @Valid=1
SET @Invalid=''
END
GO
Oracle:
CREATE OR REPLACE PROCEDURE VALID
(
Yhbh  CHAR,          --形参不需要指定长度
Password1 VARCHAR2,
Valid OUT NUMBER ,   --顺序和SQL Server相反,且输出参数的关键字为OUT
Invalid  OUT VARCHAR2
)       --在程序中输出参数也要先输入值,否则出错?
AS      --所有的局部变量、游标和类型都在这里声明。用分号隔开。不用declare。
V NUMBER(1,0);
I VARCHAR2(100);
BEGIN
SELECT valid,invalid INTO V,I FROM MEMBER WHERE id=Yhbh AND password=Password1;
IF V=0 THEN    --必须用INTO
BEGIN
Valid:=V;    --赋值语句用:=
Invalid:=I;
END;           --此处的语法和PASCAL也有区别
ELSE
BEGIN
Valid:=1;
Invalid:='';
END;
END IF;
END;
/
在 SQL Server 中,临时过程创建在 tempdb 数据库中,对于局部临时过程,在 procedure_name 前加一个数字符 (#),全局临时过程前加两个数字符 (##)。 局部临时过程只能由创建它的用户使用。运行局部临时过程的权限不能授予其他用户。用户会话结束后,局部临时过程自动被删除。所有的 SQL Server 用户均可使用全局临时过程。如果创建了全局临时过程,所有的用户均可以访问它,权限不能被显式地撤销。使用过程的最后一个用户会话结束后,全局临时过程被删除。
临时存储过程在连接到 SQL Server 的早期版本时很有用,这些早期版本不支持再次使用 Transact-SQL 语句或批处理执行计划。连接到 SQL Server 2000 的应用程序应使用 sp_executesql 系统存储过程,而不使用临时存储过程。
下面的例子给出了,如何使用 T-SQL 存储过程替代 Oracle  PL/SQL 打包的函数。Transact-SQL 版本要简单得多,因为 SQL Server 可以直接从存储过程中的 SELECT 语句返回结果集,而无需使用游标。
Oracle
Microsoft SQL Server
CREATE OR REPLACE PACKAGE STUDENT_ADMIN.P1 AS ROWCOUNT NUMBER :=0;
CURSOR C1 RETURN STUDENT%ROWTYPE;
FUNCTION S_R_S
(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
WHERE NOT EXISTS (SELECT 'X' FROM GRADE
WHERE GRADE.SSN=STUDENT.SSN) ORDER BY SSN;
FUNCTION S_R_S
(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 S_R_S
AS
SELECT FNAME+LNAME+SSN  FROM STUDENT S
WHERE NOT EXISTS(SELECT 'X' FROM 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;
/
、触发器
MS SQL Server
MS SQL Server仅有表的触发器,而且触发机制不够丰富,如插入触发器不区分单条插入还是多条插入,也不区分插入前触发还是插入后触发。碰到多条数据的插入,需要使用游标处理每条插入的数据。SQL Server的触发器都是在触发语句之后执行,而且是语句级的。也就是说一条语句只能导致一次触发,而不管它有多少行纪录被更改,它靠虚拟表inserted和deleted的存在,确保了每行纪录都能被引用。
Oracle
Oracle提供的触发器不仅有基于表的触发器,而且还有其它类型的,例如数据库级的触发器,数据库启动、数据库关闭。对于表级的触发器,区分单条插入还是多条插入,也区分插入前触发还是插入后触发。Oracle的触发器分为触发语句之前执行或者触发语句之后执行,语句级或者行级组合起来的4种方式。
ORACLE产生数据库触发器的语法为:
create [or replace] trigger 触发器名 触发时间 触发事件  on  表名  [for each row]
其中:
触发器名:触发器对象的名称。由于触发器是数据库自动执行的,因此该名称只是一个名称,没有实质的用途。
触发时间:指明触发器何时执行,该值可取:
before--表示在数据库动作之前触发器执行;
after --表示在数据库动作之后出发器执行。
触发事件:指明哪些数据库动作会触发此触发器:
insert: 数据库插入会触发此触发器;
update: 数据库修改会触发此触发器;
delete: 数据库删除会触发此触发器。
表 名:数据库触发器所在的表。
for each row:对表的每一行触发器执行一次。如果没有这一选项,则只对整个表执行一次。
举例:下面的触发器在更新表auths之前触发,目的是不允许在周末修改表:
create  trigger  auth_secure  before  insert or update or delete //对整表更新前触发
on auths
begin
if(to_char(sysdate,'DY')='SUN'
RAISE_APPLICATION_ERROR(-20600,'不能在周末修改表auths');
end if;
end
将SQL Server的触发器移植至Oracle上,需要创建一个触发语句之后的行级触发器,一定要用行级触发器而不能用语句级触发器.因为Oracle的触发器模式中没有像SQL Server那样的inserted和deleted虚表的存在,而只有:new和:old。:new和:old不能算成是二维的表,它只是纪录字段更新之前的值和更新之后的值. 在Oracle中,游标的概念贯穿整个PL/SQL,游标在Oracle中被广泛应用.就连每一个update语句和delete语句都有一个内置的隐式的游标!因此,我们可以使用行级触发器加:old及:new来达到SQL Server中的语句级触发器加inserted及deleted的效果.例程如下: (级联删除)
SQL Server:
create trigger Ca_Del on table1
for delete
as
if @@rowcount=0
return
delete table2 from table2 t,deleted d
where t.e0 = d.b0 and t.e1 = d.b1 and t.e2 = d.b2
if @@error <> 0
goto error_handler
return
error_handler:
begin
rollback transaction
return
end
Oracle:
create or replace trigger Ca_Del
AFTER delete
on table1
for EACH ROW
begin
delete from table2
where e0 = :OLD.b0 and e1 = :OLD.b1 and e2 = :OLD.b2;
exception
when others then
rollback;
end Ca_Del;
、视图
在 Microsoft SQL Server 中,用于创建视图的语法与 Oracle 相似。
Oracle
Microsoft SQL Server
CREATE [OR REPLACE] [FORCE |
NOFORCE] VIEW [schema.]view_name
[(column_name [, column_name]...)]
AS select_statement
[WITH CHECK OPTION [CONSTRAINT
name]]
[WITH READ ONLY]
CREATE VIEW [ < database_name > .] [ < owner > .] view_name [ ( column [ ,...n ] ) ]
[ WITH < view_attribute > [ ,...n ] ]
AS select_statement
[ WITH CHECK OPTION ]
< view_attribute > ::=
{ ENCRYPTION | SCHEMABINDING | VIEW_METADATA }
SQL Server 的视图要求该表存在,并且视图所有者有权访问 SELECT 语句中所指定的表(与 Oracle FORCE 选项类似)。
默认情况下,并不检查视图上的数据修改语句,来确定受影响的行是否在视图的作用域内。要检查所有的修改,则使用 WITH CHECK OPTION。WITH CHECK OPTION 的主要差异在于,Oracle 将其定义为一个约束,而 SQL Server 没有。其它方面,两者是相同的。
定义视图时,Oracle 提供了 WITH READ ONLY 选项。通过将 SELECT 权限仅授予视图用户,SQL Server 应用程序也可获得相同的结果。
当一个视图是由外部联接定义的,并使用该联接内表一个列上的限定条件进行查询时,SQL Server 和 Oracle 给出的结果可能不同。在大多数情况下,Oracle 视图可以方便地转成 SQL Server 视图。
Oracle
Microsoft SQL Server
CREATE  VIEW S_A.SGPA(SSN, GPA)
AS SELECT SSN, ROUND(AVG(DECODE(grade
,'A',  4
,'A+', 4.3
,'A-', 3.7
,0)),2)
FROM S_A.GRADE
GROUP BY SSN
CREATE VIEW S_A.SGPA(SSN, GPA)
AS SELECT SSN, ROUND(AVG(CASE grade
WHEN 'A'  THEN 4
WHEN 'A+' THEN 4.3
WHEN 'A-' THEN 3.7
ELSE 0
END),2)
FROM S_A.GRADE
GROUP BY SSN
、关于游标
MS SQL Server
DECLARE abc CURSOR FOR SELECT * FROM authors
Oracle
DECLARE CURSOR abc IS  SELECT * FROM authors
PL/SQL用游标来管理SQL的select语句。游标是为处理这些语句而分配的一大块内存。游标定义类似于其他变量。显式游标(Explicit Cursor)要声明(Declare),在使用前要打开(Open),使用完毕要关闭(Close)。使用隐式游标(Implicit Cursor)时,用户无需执行上述步骤,只要简单地编码select语句并让PL/SQL根据需要处理游标即可。与循环结构结合的显式游标处理返回多于一行的Select语句。与循环结合的游标将允许你每次处理一行。当Select语句预计只返回一行时,隐式游标将做得更好。
使用隐式游标要注意以下几点:
&S226; 每个隐式游标必须有一个into。
- -以下不正确
if this_value > 0 THEN
select count(*) from person;
end if;
- -以下正确
if this_value > 0 then
select count(*) into cnter from person;
end if;
&S226; 和显式游标一样,“into”后的变量类型要与表列的类型一致。
&S226; 隐式游标一次仅返回一行,使用时必须检查异常。
最常见的异常为
“no_data_found”和“too_many_rows”。
. . . . . .
if counter>=10 then
begin
select age into v_age from person where pin =pin_value;
exception
when too_many_rows then
insert into taba values(pin_value,sysdate);
when no_data_found then
null;
end;
end if;
. . . . . .
/
隐式游标的一个例子:本例将通过某人社会保险号码查询其出生日期。
create or replace procedure get_dob(ss_num varchar2,dob out date)
as
begin                 -- 程序开始
select birth_date   -- 隐式游标
into dob            -- dob和birth_date的数据类型必须相同
from person
where soc_sec_num = ss_num;
exception when no_data_found then
error_notify(ss_num);  --调用其他过程
end;
/
隐式游标和显式游标
隐式游标
显式游标
PL/SQL维护,当执行查询时自动打开和关闭
在程序中显式定义、打开、关闭,游标有一个名字。
游标属性前缀是SQL
游标属性的前缀是游标名
属性%ISOPEN总是为FALSE
%ISOPEN根据游标的状态确定值
SELECT语句带有INTO子串,只有一行数据被处理
可以处理多行数据,在程序中设置循环,取出每一行数据。
操作
Oracle
Microsoft SQL Server
声明游标
CURSOR cursor_name
[(cursor_parameter(s))]
IS select_statement;
DECLARE  cursor_name
CURSOR
[LOCAL | GLOBAL]
[FORWARD_ONLY | SCROLL]
[STATIC | KEYSET | DYNAMIC | FAST_FORWARD]
[READ_ONLY | SCROLL_LOCKS | OPTIMISTIC]
[TYPE_WARNING]
FOR select_statement
[FOR UPDATE [OF column_name [,Un]]]
打开游标
OPEN cursor_name
[(cursor_parameter(s))];
OPEN cursor_name
从游标中提取
FETCH cursor_name INTO
variable(s)
FETCH [[NEXT | PRIOR | FIRST | LAST | ABSOLUTE {n | @nvar} | RELATIVE {n | @nvar}]
FROM] cursor_name
[INTO @variable(s)]
更新提取的行
UPDATE table_name
SET statement(s)U
WHERE  CURRENT  OF
cursor_name;
UPDATE table_name
SET statement(s)U
WHERE  CURRENT   OF
cursor_name
删除提取的行
DELETE FROM table_name
WHERE  CURRENT  OF
cursor_name;
DELETE FROM table_name
WHERE  CURRENT   OF
cursor_name
关闭游标
CLOSE cursor_name;
CLOSE cursor_name
删除游标数据结构
暂缺
DEALLOCATE cursor_name
其它
1、 CLOSE CURSOR 语句关闭并
释放所有的数据结构
2、只能向前移动,不能向后或相对滚动
1、 CLOSE CURSOR 语句关闭
游标,但数据结构仍可用于重新
打开游标。
2、 不支持 Oracle 的游标 FOR
循环语法
注:在Oracle中更新和删除游标要注意以下事项
UPDATE或DELETE语句中的WHERE CURRENT OF子串专门处理要执行UPDATE或DELETE操作的表中取出的最近的数据。要使用这个方法,在声明游标时必须使用FOR UPDATE子串,当对话使用FOR UPDATE子串打开一个游标时,所有返回集中的数据行都将处于行级(ROW-LEVEL)独占式锁定,其他对象只能查询这些数据行,不能进行UPDATE、DELETE或SELECT...FOR UPDATE操作。
语法:
FOR UPDATE [OF [schema.]table.column[,[schema.]table.column]..
[nowait]
在多表查询中,使用OF子句来锁定特定的表,如果忽略了OF子句,那么所有表中选择的数据行都将被锁定。如果这些数据行已经被其他会话锁定,那么正常情况下ORACLE将等待,直到数据行解锁。
在UPDATE和DELETE中使用WHERE CURRENT OF子串的语法如下:
WHERE{CURRENT OF cursor_name|search_condition}
例:
DELCARE
CURSOR c1 IS SELECT empno,salary
FROM emp
WHERE comm IS NULL
FOR UPDATE OF comm;
v_comm NUMBER(10,2);
BEGIN
FOR r1 IN c1 LOOP
IF r1.salary<500 THEN
v_comm:=r1.salary*0.25;
ELSEIF r1.salary<1000 THEN
v_comm:=r1.salary*0.20;
ELSEIF r1.salary<3000 THEN
v_comm:=r1.salary*0.15;
ELSE
v_comm:=r1.salary*0.12;
END IF;
UPDATE emp;
SET comm=v_comm
WHERE CURRENT OF c1l;
END LOOP;
END
的游标 FOR循环语法
示例1:
DECLARE
CURSOR  C1  IS
SELECT  VIEW_NAME  FROM ALL_VIEWS  WHERE  ROWNUM<=10 ORDER BY
VIEW_NAME;
BEGIN
FOR  I  IN  C1  LOOP
DBMS_OUTPUT.PUT_LINE(I.VIEW_NAME);
END LOOP;
EXCEPTION WHEN OTHERS THEN
NULL;
END;
示例2:
. . .
declare
cursor region_cur is  select first_name,last_name,ssn from person
where region_number = region_number_in;
begin
for region_rec in region_cur
loop   --请注意:在select语句中所有列自动地产生record_name.column_name
if region_rec.ssn is null then          --(即:region_rec.last_name)
insert into e_msg values(pin_in,'no ssnum');
else
insert into e_tab values(pin_in,sysdate);
end if;
end loop;
end ;
. . .
/
中带参数的游标
与存储过程和函数相似,可以将参数传递给游标并在查询中使用。这对于处理在某种条件下打开游标的情况非常有用。它的语法如下:
CURSOR cursor_name[(parameter[,parameter],...)] IS select_statement;
定义参数的语法如下:
Parameter_name [IN] data_type[{:=|DEFAULT} value]
与存储过程不同的是,游标只能接受传递的值,而不能返回值。参数只定义数据类型,没有大小。
另外可以给参数设定一个缺省值,当没有参数值传递给游标时,就使用缺省值。游标中定义的参数只是一个占位符,在别处引用该参数不一定可靠。
在打开游标时给参数赋值,语法如下:
OPEN cursor_name[value[,value]....];
参数值可以是文字或变量。
例:
DECLARE
CURSOR C1(PAT  VARCHAR2)  IS
SELECT  NAME  FROM ALL_VIEWS
WHERE  NAME  LIKE  PAT||'%'  AND   ROWNUM<=10
ORDER  BY  NAME;
VNAME  VARCHAR2(40);
BEGIN
FOR  I  IN  C1('USER_AR')  LOOP
DBMS_OUTPUT.PUT_LINE(I.NAME);
END LOOP;
DBMS_OUTPUT.PUT_LINE();
FOR  I  IN  C1('USER')     LOOP
DBMS_OUTPUT.PUT_LINE(I.NAME);
END LOOP;
EXCEPTION WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('AAA');
END;
中属性
属性
含量
%FOUND
布尔型属性,当最近一次读该记录时成功返回,则值为TRUE
%NOTFOUND
布尔型属性,它的值总与%FOUND属性的值相反
%ISOPEN
布尔型属性,当游标是打开时返回TRUE
%ROWCOUNT
数字型属性,返回已从游标中读取的记录数
注:隐式游标只使用SQL%FOUND,SQL%NOTFOUND,SQL%ROWCOUNT三个属性。
例程如下:
DECLARE
CURSOR C1 IS SELECT VIEW_NAME FROM ALL_VIEWS
WHERE ROWNUM<=10
ORDER BY VIEW_NAME;
VNAME VARCHAR2(40);
BEGIN
OPEN C1;
FETCH C1 INTO VNAME;
WHILE  C1%FOUND  LOOP
DBMS_OUTPUT.PUT_LINE(TO_CHAR(C1%ROWCOUNT)||' '||VNAME);
FETCH C1 INTO VNAME;
END LOOP;
END;
和 T-SQL 中对等的游标语句。
Oracle
Microsoft SQL Server
DECLARE
VSSN CHAR(9);
VFNAME VARCHAR(12);
VLNAME VARCHAR(20);
DECLARE
@VSSN CHAR(9),
@VFNAME VARCHAR(12),
@VLNAME VARCHAR(20)
CURSOR curl IS
SELECT SSN, FNAME, LNAME
FROM STUDENT ORDER BY LNAME;
BEGIN
OPEN CUR1;
FETCH CUR1 INTO VSSN, VFNAME, VLNAME;
WHILE (CUR1%FOUND) LOOP
FETCH CUR1 INTO VSSN, VFNAME, VLNAME;
END LOOP;
CLOSE CUR1;
END;
DECLARE curl CURSOR FOR
SELECT SSN, FNAME, LNAME
FROM STUDENT ORDER BY SSN
OPEN CUR1
FETCH NEXT FROM CUR1
INTO @VSSN, @VFNAME, @VLNAME
WHILE (@@FETCH_STATUS <> -1)
BEGIN
FETCH NEXT FROM CUR1 INTO @VSSN, @VFNAME, @VLNAME
END
CLOSE CUR1
DEALLOCATE CUR1
1、
SQL Server中的 identity 特性给我们的工作带来了很大的方便,我们可以利用它方便的进行排序.但是在Oracle中却没有这样的特性.Oracle只有 sequence 的概念.sequence 是事务无关性的,sequence 并不是依附在表的上面,它是独立存在的,和事务是无关的。但是我们只有利用sequence 来达到SQL SERVER中 identity 的效果,比较麻烦。例程如下:
SQL Server:
create table T1 -- 应收票据变动
(
f0  TYPE_v_CMPID  not null, -- 公司类别(这是个自定义类型,下同。)
f1  varchar(20)   not null, -- 票据号码
f2  int IDENTITY  not null, -- 流水号
f3  TYPE_v_DATE   null , -- 状况处理日
f4  TYPE_v_ENUM   null , -- 状况
f6  varchar(20)   null , -- 传票管理编号
f7  varchar(2)    null , -- 票据变动类别
f8  varchar(20)   null , -- 票据变动单号
constraint PK_T1 primary key (f0, f1, f2)
)
移植至Oracle中:
create table T1 -- 应收票据变动
(
f0  varchar2(3)  not null, -- 公司类别
f1  varchar2(20) not null, -- 票据号码
f2  int          not null, -- 流水号  /* SEQUENCE */
f3  varchar2(8)  null , -- 状况处理日
f4  varchar2(1)  null , -- 状况
f6  varchar2(20) null , -- 传票管理编号
f7  varchar2(2)  null , -- 票据变动类别
f8  varchar2(20) null , -- 票据变动单号
constraint PK_T1 primary key (f0, f1, f2)
);
CREATE SEQUENCE T1_seq  INCREMENT BY  1; //创建一个序列
create or replace TRIGGER T1_insert_before //增加一个insert之前的触发器
before insert on T1
for each row
declare
i_id integer;
begin
select T1_seq.nextval into i_id from dual;
:NEW.f2 := i_id;
end;
但是有一个地方需要注意:sequence 的值不能被手工重置,在 SQL Server 中可以通过
dbcc checkident(表名,reseed,0)或者truncate table tableName(如果数据也不需要的话)将表中的identity字段重置为1,而Oracle的sequence做不到这点,sequence只有达到最大值后,系统才会自动将其重置为预定的最小值。
Sequence的语法如下:建立一个最小为1,最大为999999999的一个序列号会自动循环的序列
create sequence 序列名 increment by 1 start with 1 maxvalue 999999999 cycle;
当向表中插入数据时,SQL语句如下:insert into 表名 values(序列名.nextval,列1值,列2值);
2、
在SQL Server中可以用top n 来返回指定数量的纪录,Oracle中与之对应的是 rownum,只
是不同的是:SQL Server的top n 是逻辑顺序返回的纪录,而Oracle的 rownum 指定的是物理顺
序的序号,其物理的序号是在order by之前就已经决定好了的.因此下面的语句在Oracle中都是
错误的:
错误语句1:
select rownum,fom01.*  from fom01 where rownum < 11 order by foa02d;
//这条语句永远也得不到正确的,因为 rownum 是物理顺序的序号,是在排序之前就已经决定好了的.
纠正后的语句:
select rownum,ss.* from (select * from fom01 order by foa02d) ss where rownum < 11;
//据说Oracle8I以前的版本在子查询中不能使用order by?
错误语句2:
select rownum,fom01.* from fom01 where rownum = 2;
//这条语句将返回不了任何的值,但是将2改成1就可以返回一条纪录。因为Oracle的rownum只有在生成了1后才能有2,同样的有了2才能有3,以此类推.
纠正后的语句:
select * from (select rownum  r, fom01.*  from fom01  where rownum <= 2)
where r > 1;
用rownum实现大于、小于逻辑(返回rownum在4—10之间的数据)(minus操作,速度会受影
响)
SQL> select rownum,month,sell from sale where rownum<10
2  minus
3  select rownum,month,sell from sale where rownum<5;
3、执行动态SQL
一个动态SQL语句是在运行时而不是在编译时建立和执行的,在编译时,用户如果不了解查询的结构或者想要查询的对象,就可以使用动态SQL.但是一般而言,运行动态SQL的系统资源花费是运行同样的静态SQL的两到三倍.因为每次执行动态SQL的时候都必须重新对它进行语法分析.由于此点因素,尽可能的少使用动态SQL.
SQL Server:
SQL Server用exec('字符串')可以执行动态SQL,如果需要从执行的动态SQL中得到结果值的话可以用sp_executesql存储过程,例程如下:
declare @count int
declare @SQL nvarchar(200)
set @SQL = N'select count(*) from sysobjects'
exec sp_executesql @SQL,N'@i int output',@count output
print @count
Oracle:
在Oracle中,可以使用DBMS_SQL包和execute immediate '……’来执行动态SQL,不过听说execute immediate '……’在Oracle8及以前的版本中是不能使用的,例程如下:
set serveroutput on
/
declare
i_count int ;
v_SQL varchar2(200) := 'begin select count(*) into :1 from user_objects; end;';
begin
execute immediate v_SQL using out i_count;
dbms_output.put_line(i_count);
end;
/
DBMS_SQL包使用起来较为复杂繁琐而且显式使用光标,不提倡使用,但有一点需要注意 execute immediate 所能执行的字符串的长度是有限制的,如果超过了这个限制,那么只能用DBMS_SQL包了.
EXECUTE IMMEDIATE 的使用技巧:
1.     EXECUTE IMMEDIATE  将不会提交一个DML事务执行,应该显式提交 如果通过EXECUTE
IMMEDIATE处理DML命令,那么在完成以前需要显式提交或者作为EXECUTE  IMMEDIATE
自己的一部分。如果通过EXECUTE IMMEDIATE处理DDL命令,它提交所有以前改变的数据。
2.     不支持返回多行的查询,这种交互将用临时表来存储记录(参照例子如下)或者用REF
cursors。.
3. 当执行SQL语句时,不要用分号,当执行PL/SQL块时,在其尾部用分号。
下面的例子展示了所有用到Execute immediate的可能方面,希望能给你带来方便:
1.在PL/SQL中运行DDL语句:
begin
execute immediate 'set role all';
end;
2. 给动态语句传值(USING 子句)
declare
l_depnam varchar2(20) := 'testing';
l_loc    varchar2(10) := 'Dubai';
begin
execute immediate 'insert into dept values  (:1, :2, :3)'
using 50, l_depnam, l_loc;
commit;
end;
3. 从动态语句检索值(INTO子句)
declare
l_cnt    varchar2(20);
begin
execute immediate 'select count(1) from emp'
into l_cnt;
dbms_output.put_line(l_cnt);
end;
3.     动态调用例程.例程中用到的绑定变量参数必须指定参数类型.黓认为IN类型,其它类型必须显式指定
declare
l_routin   varchar2(100) := 'gen2161.get_rowcnt';
l_tblnam   varchar2(20) := 'emp';
l_cnt       number;
l_status   varchar2(200);
begin
execute immediate 'begin ' || l_routin || '(:2, :3, :4); end;'
using in l_tblnam, out l_cnt, in out l_status;
if l_status != 'OK' then
dbms_output.put_line('error');
end if;
end;
5. 将返回值传递到PL/SQL记录类型;同样也可用%rowtype变量
Declare
type empdtlrec is record (empno  number(4),
ename  varchar2(20),
deptno  number(2));
empdtl empdtlrec;
begin
execute immediate 'select empno, ename, deptno ' ||
'from emp where empno = 7934'
into empdtl;
end;
6. 传递并检索值.INTO子句用在USING子句前
declare
l_dept    pls_integer := 20;
l_nam     varchar2(20);
l_loc     varchar2(20);
begin
execute immediate 'select dname, loc from dept where deptno = :1'
into l_nam, l_loc
using l_dept ;
end;
7. 多行查询选项.对此选项用insert语句填充临时表,用临时表进行进一步的处理,也可以用REF cursors纠正此缺憾.
declare
l_sal   pls_integer := 2000;
begin
execute immediate 'insert into temp(empno, ename) ' ||
'          select empno, ename from emp ' ||
'          where  sal > :1'
using l_sal;
commit;
end;
4、函数的比较
学函数
函数
Oracle
Microsoft SQL Server
绝对值
ABS
ABS
反余弦
ACOS
ACOS
反正弦
ASIN
ASIN
n 的反正切
ATAN
ATAN
m/n 的反正切
ATAN2
ATN2
>=值的最小整数
CEIL
CEILING
余弦
COS
COS
双曲余弦
COSH
COT
指数值
EXP
EXP
<=值的最大整数
FLOOR
FLOOR
自然对数
LN
LOG
以任何为底的对数
LOG(N)
暂缺
以 10 为底的对数
LOG(10)
LOG10
模数(余数)
MOD
USE MODULO (%) OPERATOR

POWER
POWER
随机数
暂缺
RAND
舍入
ROUND
ROUND
数的符号
SIGN
SIGN
正弦
SIN
SIN
双曲正弦
SINH
暂缺
平方根
SQRT
SQRT
正切
TAN
TAN
双曲正切
TANH
暂缺
截尾
TRUNC
暂缺
列表中的最大数
GREATEST
暂缺
列表中的最小数
LEAST
暂缺
如果为 NULL,转换成数字
NVL
ISNULL
函数
Oracle
Microsoft SQL Server
把字符转换成 ASCII
ASCII
ASCII
字符串串联
CONCAT
(表达式 + 表达式)
把 ASCII 转换成字符
CHR
CHAR
返回字符串中的起始字符(从左)
INSTR
CHARINDEX
将字符转换成小写
LOWER
LOWER
将字符转换成大写
UPPER
UPPER
在字符串的左边填充字符
LPAD*
暂缺
删除前导空格
LTRIM
LTRIM
删除尾空格
RTRIM
RTRIM
字符串中模式的起始点
INSTR
PATINDEX
多次重复字符串
RPAD
REPLICATE
字符串的语音表示
SOUNDEX
SOUNDEX
重复空格的字符串
RPAD
SPACE
从数字数据转换而来的字符数据
TO_CHAR
STR
子字符串
SUBSTR***
SUBSTRING、LEFT、RIGHT
字符替换
REPLACE
STUFF
字符串中每个词的第一个字母大写
INITCAP
暂缺
字符串转换
TRANSLATE
暂缺
字符串长度
LENGTH
DATELENGTH 或 LEN
列表中的最大字符串
GREATEST
暂缺
列表中的最小字符串
LEAST
暂缺
如果为 NULL,则转换字符串
NVL**
ISNULL
*LPAD(char1,n,char2)函数
解释:
字符char1按制定的位数n显示,不足的位数用char2字符串替换左边的空位
**NVL(EXPR1, EXPR2)函数
解释:
IF EXPR1=NULL
RETURN EXPR2
ELSE
RETURN EXPR1
***SUBSTR
解释:它具有SQL Server中SUBSTRING、LEFT、RIGHT三者的功能
SUBSTR('abcd',1,2) 返回ab,
SUBSTR('abcd',-2,2) 返回cd。
函数
Oracle
Microsoft SQL Server
日期加
(日期列 +/- 值)或 ADD_MONTHS
DATEADD
日期间的间隔
(日期列 +/- 值)或 MONTHS_BETWEEN
DATEDIFF
当前日期和时间
SYSDATE
GETDATE()
月的最后一天
LAST_DAY
暂缺
时区转换
NEW_TIME
暂缺
该日期后的第一个工作日
NEXT_DAY
暂缺
日期的字符串表示
TO_CHAR*
DATENAME**
日期的整数表示
TO_NUMBER (TO_CHAR))*
DATEPART**
日期舍入
ROUND
CONVERT
日期截尾
TRUNC
CONVERT
字符串转换为日期
TO_DATE
CONVERT
如果为 NULL,则转换日期
NVL
ISNULL
*另:oracle常用日期数据格式(用TO_CHAR或TO_NUMBER函数)
**SQL Server常用日期数据格式(用DATENAME或DATEPART函数)
函数
Oracle
Microsoft SQL Server
数字到字符
TO_CHAR
CONVERT
字符到数字
TO_NUMBER
CONVERT
日期到字符
TO_CHAR
CONVERT
字符到日期
TO_DATE
CONVERT
十六进制到二进制
HEX_TO_RAW
CONVERT
二进制到十六进制
RAW_TO_HEX
CONVERT
函数
Oracle
Microsoft SQL Server
返回第一个非空表达式
DECODE
COALESCE
当前序列值
CURRVAL
暂缺
下一个序列值
NEXTVAL
暂缺
如果表达式 1 = 表达式 2,则返回空
DECODE
NULLIF
用户的登录 ID 号
UID
SUSER_ID
用户的登录名
USER
SUSER_NAME
用户的数据库 ID 号
UID
USER_ID ([ 'user'])
给定标识号的用户数据库用户名
USER
USER_NAME ([ id ])
当前用户
CURRENT_USER
CURRENT_USER
用户环境(审核记录)
USERENV
暂缺
CONNECT BY 子句的级别
LEVEL
暂缺
函数
Oracle
Microsoft SQL Server
平均值
AVG
AVG
计数
COUNT
COUNT
最大值
MAX
MAX
最小值
MIN
MIN
标准偏差
STDDEV
STDEV 或 STDEVP
汇总
SUM
SUM
方差
VARIANCE
VAR 或 VARP
5、的差异
SQL Server 聚集索引和 Oracle 聚集索引没有任何相同之处。Oracle 聚集是两个或多个表的物理组合,这些表共享相同的数据块,并使用公共列作为聚集键。在 SQL Server 中,没有与 Oracle 聚集相似的结构。
在 SQL Server 中,删除和重新创建聚集索引是重组表的一种常用技巧。使用这种方法,可以很容易地保证在磁盘上的页是连续的,且可以在表上方便地重建一些可用空间。这与 Oracle 中的导出、删除和导入表类似。原则上,在表上定义聚集索引可改善 SQL Server 性能和空间管理。如果不了解给定表的查询或更新模式,可在主键上创建聚集索引。 一旦在表上施加了 PRIMARY KEY 或 UNIQUE 约束,Microsoft SQL Server 就会自动为该表创建一个聚集索引。
请注意下表SQL Server 聚集索引的使用。
Oracle
Microsoft SQL Server
CREATE TABLE STUDENT (
SSN CHAR(9) NOT NULL,
CCODE VARCHAR2(4) NOT NULL,
GRADE VARCHAR2(2) NULL,
CONSTRAINT GRADE_SSN_CCODE_PK
PRIMARY KEY (SSN, CCODE)
CONSTRAINT GRADE_SSN_FK
FOREIGN KEY (SSN) REFERENCES
STUDENT_ADMIN.STUDENT (SSN),
CONSTRAINT GRADE_CCODE_FK
FOREIGN KEY (CCODE) REFERENCES
DEPT_ADMIN.CLASS (CCODE)
)
CREATE TABLE STUDENT (
SSN CHAR(9) NOT NULL,
CCODE VARCHAR(4) NOT NULL,
GRADE VARCHAR(2) NULL,
CONSTRAINT
GRADE_SSN_CCODE_PK
PRIMARY KEY CLUSTERED (SSN, CCODE),
CONSTRAINT GRADE_SSN_FK
FOREIGN KEY (SSN) REFERENCES
STUDENT_ADMIN.STUDENT (SSN),
CONSTRAINT GRADE_CCODE_FK
FOREIGN KEY (CCODE) REFERENCES
DEPT_ADMIN.CLASS (CCODE)
)
在非聚集索引中,索引数据和表数据在物理上是分离的,且表中的行不按照索引的顺序存储。可以把 Oracle 索引定义迁移到 Microsoft SQL Server 非聚集索引定义(如下面例子所示)。但是,出于性能方面的考虑,可能希望选择给定表的一个索引,并把它创建为聚集索引。
Oracle
Microsoft SQL Server
CREATE INDEX
S_A.STUDENT_MAJOR_IDX
ON S_A.STUDENT (MAJOR)
TABLESPACE USER_DATA
PCTFREE 0
STORAGE (INITIAL 10K NEXT 10K
MINEXTENTS 1 MAXEXTENTS
UNLIMITED)
CREATE NONCLUSTERED INDEX
STUDENT_MAJOR_IDX
ON USER_DB.S_A.STUDENT (MAJOR)
在 Oracle 中,索引名在用户帐户中是唯一的。在 Microsoft SQL Server 中,索引名在表名称中必须是唯一的,但在用户帐户或数据库中则不一定是唯一的。因此,在 SQL Server 中创建或删除索引时,必须指明表的名称和索引名称。此外,SQL Server DROP INDEX 语句可以同时删除多个索引。
Oracle
Microsoft SQL Server
CREATE [UNIQUE] INDEX [schema].index_name
ON [schema.]table_name (column_name
[, column_name]...)
[INITRANS n]
[MAXTRANS n]
[TABLESPACE tablespace_name]
[STORAGE storage_parameters]
[PCTFREE n]
[NOSORT]
DROP INDEX ABC;
CREATE [UNIQUE] [CLUSTERED | NONCLUSTERED]
INDEX index_name ON table (column [,Un])
[WITH
[PAD_INDEX]
[[,] FILLFACTOR = fillfactor]
[[,] IGNORE_DUP_KEY]
[[,] DROP_EXISTING]
[[,] STATISTICS_NORECOMPUTE]
]
[ON filegroup]
DROP INDEX USER_DB.STUDENT.DEMO_IDX, USER_DB.GRADE.DEMO_IDX
Microsoft SQL Server 中 FILLFACTOR 选项和 Oracle 中的 PCTFREE 变量的作用基本相同。随着表的增大,索引页就会拆分,以容纳新数据。索引必须重新组织,来容纳新的数据值。填充因子百分比只在索引创建时使用,以后不再维护。
在索引最初创建时,FILLFACTOR 选项(值从 0 到 100 )控制索引页上保留多少空间。如果没有指定,使用默认的填充因子 0 - 这将完全填充索引叶级页,并在每个决定节点页上保留至少一个条目的空间(对于非唯一的聚集索引保留两个)。
使用较低的填充因子值,最初会减少索引页的拆分,并增加 B 树索引结构中级别的数目。使用较高的填充因子值,可更有效地使用索引页空间,访问索引数据需要较少的磁盘 I/O,并减少了 B 树索引结构中级别的数目。
PAD_INDEX 选项指定了,将填充因子应用到索引的决定节点页以及数据页中。
尽管在 Oracle 中,必须调整 PCTFREE 参数来优化性能,但在 CREATE INDEX 语句中,一般不需要加入 FILLFACTOR 选项。填充因子可用于优化性能。仅当使用现有数据在表上创建新索引,并且能够准确预估该数据以后的变化时,填充因子才是有用的。
如果已经把 Oracle 索引的 PCTFREE 设为 0,则考虑使用值为 100 的填充因子。它用于不发生插入和更新的表(只读表)。填充因子设为 100 时,SQL Server 创建每页均百分之百填充的索引。
在oracle中, select,update,delete 语句中的子查询应当有规律地查找少于20%的表行.如果一个语句查找的行数超过总行数的20%,它将不能通过使用索引获得性能上的提高.
索引可能产生碎片,因为记录从表中删除时,相应也从表的索引中删除.表释放的空间可以再用,而索引释放的空间却不能再用.频繁进行删除操作的被索引的表,应当阶段性地重建索引,以避免在索引中造成空间碎片,影响性能.在许可的条件下,也可以阶段性地truncate表,truncate命令删除表中所有记录,也删除索引碎片.
Oracle9i增强了全索引SQL执行计划以支持基于功能的索引(function-based index)。一旦存在索引,Oracle就会绕过对表的访问,索引组织表(index-organized table,IOT)结构就是一个例子。在IOT结构中,所有的数据都载入索引的b-树结构,这样表(table)就成为一个多余的东西了。
一旦Oracle SQL优化器检测到查询无需访问表时,Oracle就调用全索引扫描并快速读取每一个索引块而无需接触表本身。有一点很重要:全索引扫描并没有读取索引节点,而是一块一块的执行扫描并快速捕获索引节点。最好,Oracle调用多块读取功能,调用多个过程来读取表。
为了加快表和索引的访问速度,Oracle使用了db_file_multiblock_read_count参数(默认参数为8)来辅助把全表扫描和全索引扫描所获得的数据块尽快送到数据缓冲区中。然而,这个参数只有当SQL查询执行全表扫描时才可用,并且,在绝大多数情况下,查询要使用索引来访问表。
Oracle对全索引扫描有如下限制:
SQL请求的全部列(column)必须驻留在索引树中;也就是说,SELECT和WHERE字句中的所有数据列必须存在于索引中。 查询访问大量的行(row)。根据你查询的范围,比例变化范围为10%到25%之间,这个比例参数db_file_multiblock_read_count的设置和查询的并行程度极大的影响到这个比例。 由于索引节点并没有按索引顺序排列,所以列并没有顺序。这样,ORDER BY字句将要求附加的排序操作。 Oracle提供了一个SQL提示(hint)来强制全索引扫描。你也可以通过指定index_ffs提示来强制快速索引扫描,这常常与parallel_index提示组合来提高性能。例如,下面的查询强迫使用并行快速全索引扫描:
select distinct /*+ index_ffs(c,pk_auto) parallel_index_
(automobile, pk_auto) color, count(*) from  automobiles group by color;
由于涉及了所有的变量,所以全索引是否会加快查询速度并不能简单的加以回答。所以,大多数有经验的SQL调试者(tuner)会对符合快速全索引扫描标准的查询进行手工计时,看看使用全索引扫描的反映时间是否会降低。
函数索引基础
在Oracle9i之前,全索引扫描只有当创建的索引没有空值时才可以使用,也就是说,Oracle建立索引时必须用一个NOT NULL子句才可以使用该索引。由于Oracle9i支持用函数(function-based)索引实现的唯索索引扫描,这种情况大大改观。
简单回归一下,函数索引是Oracle8的一个重要改进,因为它提供了一种有效的消除无必要长表全扫描的机制,由于函数索引可以在任何查询语句中的WHERE子句中精确复制,Oracle总会用一个索引来匹配上SQL查询的WHERE子句。
下面用一个简单的例子来解释全索引扫描如何与函数索引一起工作的过程。
创建student表
(student_name varchar2(40), date_of_birth date); 使用这个表,创建与表中所有列相关联的函数索引。在本例中,该函数为initcap(即大写每个单词的首字母)和to_char(即把一个数字变成字符): create index whole_student  on student(initcap(student_name), to_char(date_of_birth,’MM-DD-YY’));
定义完函数索引后,Oracle9i中任何可以引用这些列(column)的SQL语句都可以使用全索引
扫描。下面是SQL匹配函数索引的查询例子:
select * from student  where initcap(student_name) = 'Jones’;select * from student  where to_char(date_of_birth,’MM-DD=YY’) = ’04-07-85’;
用函数索引来调用全索引扫描
Oracle9i只要可能就会使用函数索引并在函数索引的基础上调用全索引扫描。如果SQL优化器统计结果表明使用全索引扫描的速度将会超过通过索引的b-树访问的速度,那么Oracle9i就会这么做。
下面是用函数索引调用唯索扫描的准则。所有的SQL谓词匹配索引中的列,查询必须从表中返回足够多的行,这样做的目的是为了让代价优化器(cost-based optimizer)来判断全索引扫描是否要比传统的索引访问方法要快。是否调用全索引扫描的决定取决于下面几个参数设置:
代价优化器的适当统计数字——这个计划(schema)最近已经分析过了,而且optimizer_mode参数不能设置为RULE。 索引的并行程度——注意索引的并行程度是独立设置的;索引并没有继承表的并行程度。 optimizer_index_cost_adj的设置——它控制代价优化器是否倾向于全索引扫描。 db_file_multiblock_read_count的设置——这个参数影响到全索引扫描的代价。这个值越高,全索引扫描的代价也就会越“便宜”。 索引的直方图表示——对偏移(skewed)索引,它帮助代价优化器评估查询返回的行数。
Oracle的一个重要提高
在函数索引基础上的快速全索引扫描是Oracle9i的另一个提高性能的途径。当数据库迁移到Oracle9i时,许多数据库自动开始使用这个新的执行计划。不过,当SQL代价优化器决定是否选择全索引扫描时,还要考虑几个因素。Oracle专业人员需要适当设置参数,以确保代价优化器不会用不合适的方式使用快速全索引扫描——这一点需要特别注意。

l         约束共有五类:
NOT NULL 指定不接受 NULL 值的列。
所有的 SQL 脚本(不论是 Oracle 还是 SQL Server)都应该为每一列显式定义 NULL 和 NOT NULL。要了解这一策略是如何实施的,请参见 Oratable.sql 和 Sstable.sql 示例表创建脚本。如果没有显式定义,列的为空性遵循下列规则。
Null 设置
说明
使用用户定义的数据类型定义列
SQL Server 使用该数据类型创建时指定的为空性。使用 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
没有定义
如果没有显式地定义(没有设置任何 ASNI_NULL_DFLT 选项),会话没有改变,并且数据库设为默认值(ANSI null default 为 false),那么,SQL Server 赋值为 NOT NULL。
CHECK 约束对可以放入列中的值进行限制,以强制执行域的完整性。
在 Oracle 和 SQL Server 中,定义 CHECK 约束的语法是相同的。搜索条件必须对一个布尔表达式进行求值,并且不能包括子查询。列级 CHECK 约束只能引用受约束的列,表级 CHECK 约束只可以引用受约束表中的列。可以为一个表定义多个 CHECK 约束。在 CREATE TABLE 语句中,SQL Server 语法规定,在一个列上只允许创建一个列级 CHECK 约束,约束可以有多个条件。
Oracle
Microsoft SQL Server
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')),
...
SQL Server的另一个例子如下:
下例显示名为 chk_id 约束的创建,该约束确保只对此关键字输入指定范围内的数字,以进一步强制执行主键的域。
CREATE TABLE cust_sample    (    cust_id                int        PRIMARY KEY,    cust_name            char(50),    cust_address            char(50),    cust_credit_limit    money,    CONSTRAINT chk_id CHECK (cust_id BETWEEN 0 and 10000 )    )UNIQUE 约束在列集内强制执行值的唯一性。
对于 UNIQUE 约束中的列,表中不允许有两行包含相同的非空值。主键也强制执行唯一性,但主键不允许空值。UNIQUE 约束优先于唯一索引。
对于完全唯一键(单个或多个列索引),SQL Server 只允许一行包含 NULL 值,而 Oracle 允许任意数量的行包含 NULL 值。 //????????
Oracle
Microsoft SQL Server
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
(DEPT VARCHAR(4) NOT NULL,
DNAME VARCHAR(30) NOT NULL,
CONSTRAINT DEPT_DEPT_PK
PRIMARY KEY CLUSTERED (DEPT),
CONSTRAINT DEPT_DNAME_UNIQUE
UNIQUE NONCLUSTERED (DNAME)
)
PRIMARY KEY 约束标识列或列集,这些列或列集的值唯一标识表中的行。
在一个表中,不能有两行包含相同的主键值。不能在主键内的任何列中输入 NULL 值。在数据库中 NULL 是特殊值,代表不同于空白和 0 值的未知值。建议使用一个小的整数列作为主键。每个表都应有一个主键。
一个表中可以有一个以上的列组合,这些组合能唯一标识表中的行,每个组合就是一个候选键。数据库管理员从候选键中选择一个作为主键。例如,在 part_sample 表中,part_nmbr 和 part_name 都可以是候选键,但是只将 part_nmbr 选作主键。
CREATE TABLE part_sample            (part_nmbr        int            PRIMARY KEY,            part_name        char(30),            part_weight        decimal(6,2),            part_color        char(15) )FOREIGN KEY 约束标识表之间的关系。
一个表的外键指向另一个表的候选键。当外键值没有候选键时,外键可防止操作保留带外键值的行。在下例中,order_part 表建立一个外键引用前面定义的 part_sample 表。通常情况下,order_part 在 order 表上也有一个外键,下面只不过是一个简单示例。
CREATE TABLE order_part        (order_nmbr        int,        part_nmbr        int            FOREIGN KEY REFERENCES part_sample(part_nmbr)                ON DELETE NO ACTION,        qty_ordered        int)GO
如果一个外键值没有候选键,则不能插入带该值(NULL 除外)的行。如果尝试删除现有外键指向的行,ON DELETE 子句将控制所采取的操作。ON DELETE 子句有两个选项:
NO ACTION 指定删除因错误而失败。 CASCADE 指定还将删除包含指向已删除行的外键的所有行。
如果尝试更新现有外键指向的候选键值,ON UPDATE 子句将定义所采取的操作。它也支持 NO ACTION 和 CASCADE 选项。
约束可以是列约束或表约束:
列约束被指定为列定义的一部分,并且仅适用于那个列。 表约束的声明与列的定义无关,可以适用于表中一个以上的列。
当一个约束中必须包含一个以上的列时,必须使用表约束。
例如,如果一个表的主键内有两个或两个以上的列,则必须使用表约束将这两列加入主键内。假设有一个表记录工厂内的一台计算机上所发生的事件。假定有几类事件可以同时发生,但不能有两个同时发生的事件属于同一类型。这一点可以通过将 type 列和 time 列加入双列主键内来强制执行。
CREATE TABLE factory_process   (event_type   int,   event_time   datetime,   event_site   char(50),   event_desc   char(1024),CONSTRAINT event_key PRIMARY KEY (event_type, event_time) )
禁用约束可以提高数据库性能和简化数据复制过程。例如,在远程站点重建或复制表数据时,不需要再重复约束检查,因为数据最初插到表中时,数据完整性已经检查过了。可以编写一个 Oracle 应用程序,禁用或启用约束(除 PRIMARY KEY 和 UNIQUE 外)。在 Microsoft SQL Server 中,将 ALTER TABLE 语句与 CHECK 和 WITH ONCHECK 选项一起使用,也可实现上述过程。
在 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
尽管 IDENTITY 属性在一个表中自动完成行编号,但不同的表(每个表均有其自己的标识符列)的属性值可能会相同。这是因为,IDENTITY 属性只保证在使用它的表中唯一。如果应用程序必须生成一个标识符列,其在整个数据库中、或者甚至每个联网计算机上的每个数据库中都是唯一,则使用 ROWGUIDCOL 属性、uniqueidentifier 数据类型和 NEWID 函数。SQL Server 使用全局唯一标识符列,来合并复制,确保在表的多个副本中,行被唯一地标识。
对于给定列,范围完整性实施了有效的条目。范围完整性是通过限制可能值的类型(通过数据类型)、格式(通过 CHECK 约束)或范围(通过 REFERENCE 和 CHECK 约束)实施的。
Oracle 把默认值作为列属性,而 Microsoft SQL Server 把默认值作为约束。SQL Server DEFAULT 约束可以包含常量、不带参数的内置函数(niladci 函数)或 NULL。
要方便地迁移 Oracle DEFAULT 列属性,应该在 SQL Server 列级中定义 DEFAULT 约束,而不必使用约束名称。对于每个 DEFAULT 约束,SQL Server 均生成一个唯一的名称。
约束
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 [..., 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
列属性,但不是约束
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 约束的使用。
实体完整性
实体完整性将行定义为特定表的唯一实体。实体完整性强制表的标识符列或主键的完整性(通过索引、UNIQUE 约束、PRIMARY KEY 约束或 IDENTITY 属性)。
域完整性
域完整性是指给定列的输入有效性。强制域有效性的方法有:限制类型(通过数据类型)、格式(通过 CHECK 约束和规则)或可能值的范围(通过 FOREIGN KEY 约束、CHECK 约束、DEFAULT 定义、NOT NULL 定义和规则)。
引用完整性
在输入或删除记录时,引用完整性保持表之间已定义的关系。在 Microsoft? SQL Server&S482; 2000 中,引用完整性基于外键与主键之间或外键与唯一键之间的关系(通过 FOREIGN KEY 和 CHECK 约束)。引用完整性确保键值在所有表中一致。这样的一致性要求不能引用不存在的值,如果键值更改了,那么在整个数据库中,对该键值的所有引用要进行一致的更改。
强制引用完整性时,SQL Server 禁止用户进行下列操作:
当主表中没有关联的记录时,将记录添加到相关表中。 更改主表中的值并导致相关表中的记录孤立。 从主表中删除记录,但仍存在与该记录匹配的相关记录。
例如,对于 pubs 数据库中的 sales 和 titles 表,引用完整性基于 sales 表中的外键 (title_id) 与 titles 表中的主键 (title_id) 之间的关系。
、优化 SQL 语句
以下是针对Oracle的一些优化方案,对SQL Server也基本一致:
SQL语句编写注意问题
在多数情况下,Oracle使用索引来更快地遍历表,优化器主要根据定义的索引来提高性能。但是,如果在SQL语句的where子句中写的SQL代码不合理,就会造成优化器删去索引而使用全表扫描,一般就这种SQL语句就是所谓的劣质SQL语句。在编写SQL语句时我们应清楚优化器根据何种原则来删除索引,这有助于写出高性能的SQL语句。
下面就某些SQL语句的where子句编写中需要注意的问题作详细介绍。在这些where子句中,即使某些列存在索引,但是由于编写了劣质的SQL,系统在运行该SQL语句时也不能使用该索引,而同样使用全表扫描,这就造成了响应速度的极大降低。
1. IS NULL 与 IS NOT NULL
不能用null作索引,任何包含null值的列都将不会被包含在索引中。即使索引有多列这样的情况下,只要这些列中有一列含有null,该列就会从索引中排除。也就是说如果某列存在空值,即使对该列建索引也不会提高性能。
任何在where子句中使用is null或is not null的语句优化器是不允许使用索引的。
2. 联接列
对于有联接的列,即使最后的联接值为一个静态值,优化器是不会使用索引的。我们一起来看一个例子,假定有一个职工表(employee),对于一个职工的姓和名分成两列存放(FIRST_NAME和LAST_NAME),现在要查询一个叫比尔.克林顿(Bill Cliton)的职工。
下面是一个采用联接查询的SQL语句,?????????
select * from employss
where
first_name||''||last_name ='Beill Cliton';
上面这条语句完全可以查询出是否有Bill Cliton这个员工,但是这里需要注意,系统优化器对基于last_name创建的索引没有使用。
当采用下面这种SQL语句的编写,Oracle系统就可以采用基于last_name创建的索引。
Select * from employee
where
first_name ='Beill' and last_name ='Cliton';
遇到下面这种情况又如何处理呢?如果一个变量(name)中存放着Bill Cliton这个员工的姓名,对于这种情况我们又如何避免全程遍历,使用索引呢?可以使用一个函数,将变量name中的姓和名分开就可以了,但是有一点需要注意,这个函数是不能作用在索引列上。下面是SQL查询脚本:
select * from employee
where
first_name = SUBSTR('&&name',1,INSTR('&&name',' ')-1)
and
last_name = SUBSTR('&&name',INSTR('&&name’,' ')+1)
3. 带通配符(%)的like语句
同样以上面的例子来看这种情况。目前的需求是这样的,要求在职工表中查询名字中包含cliton的人。可以采用如下的查询SQL语句:
Select  *  from  employee  where  last_name  like  '%cliton%';
这里由于通配符(%)在搜寻词首出现,所以Oracle系统不使用last_name的索引。在很多情况下可能无法避免这种情况,但是一定要心中有底,通配符如此使用会降低查询速度。然而当通配符出现在字符串其他位置时,优化器就能利用索引。在下面的查询中索引得到了使用:
Select  *  from  employee  where  last_name  like 'c%';
4. Order by语句
ORDER BY语句决定了Oracle如何将返回的查询结果排序。Order by语句对要排序的列没有什么特别的限制,也可以将函数加入列中(象联接或者附加等)。任何在Order by语句的非索引项或者有计算表达式都将降低查询速度。
仔细检查order by语句以找出非索引项或者表达式,它们会降低性能。解决这个问题的办法就是重写order by语句以使用索引,也可以为所使用的列建立另外一个索引,同时应绝对避免在order by子句中使用表达式。
5. NOT
我们在查询时经常在where子句使用一些逻辑表达式,如大于、小于、等于以及不等于等等,也可以使用and(与)、or(或)以及not(非)。NOT可用来对任何逻辑运算符号取反。下面是一个NOT子句的例子:
... where not (status ='VALID')
如果要使用NOT,则应在取反的短语前面加上括号,并在短语前面加上NOT运算符。NOT运算符包含在另外一个逻辑运算符中,这就是不等于(<>)运算符。换句话说,即使不在查询where子句中显式地加入NOT词,NOT仍在运算符中,见下例:
... where status <>'INVALID';
再看下面这个例子:
select * from employee where  salary<>3000;
对这个查询,可以改写为不使用NOT:
select * from employee where  salary<3000 or salary>3000;
虽然这两种查询的结果一样,但是第二种查询方案会比第一种查询方案更快些。第二种查询允许Oracle对salary列使用索引,而第一种查询则不能使用索引。
6.  IN和EXISTS
有时候会将一列和一系列值相比较。最简单的办法就是在where子句中使用子查询。在where子句中可以使用两种格式的子查询。
第一种格式是使用IN操作符:
... where  column  in  (select  *  from ... where ...);
第二种格式是使用EXIST操作符:
... where  exists  (select  'X'   from ...where ...);
我相信绝大多数人会使用第一种格式,因为它比较容易编写,而实际上第二种格式要远比第一种格式的效率高。在Oracle中可以几乎将所有的IN操作符子查询改写为使用EXISTS的子查询。
第二种格式中,子查询以'select 'X'开始。运用EXISTS子句不管子查询从表中抽取什么数据它只查看where子句。这样优化器就不必遍历整个表而仅根据索引就可完成工作(这里假定在where语句中使用的列存在索引)。相对于IN子句来说,EXISTS使用相连子查询,构造起来要比IN子查询困难一些。
通过使用EXIST,Oracle系统会首先检查主查询,然后运行子查询直到它找到第一个匹配项,这就节省了时间。Oracle系统在执行IN子查询时,首先执行子查询,并将获得的结果列表存放在在一个加了索引的临时表中。在执行子查询之前,系统先将主查询挂起,待子查询执行完毕,存放在临时表中以后再执行主查询。这也就是使用EXISTS比使用IN通常查询速度快的原因。
同时应尽可能使用NOT EXISTS来代替NOT IN,尽管二者都使用了NOT(不能使用索引而降低速度),NOT EXISTS要比NOT IN查询效率更高。
7.  其它
SET 语句可以为工作会话期、触发器或存储过程运行期设定 SQL Sever 查询处理选项。
SET FORCEPLAN ON 语句强制优化程序按照表在 FROM 子句中出现的顺序处理联接,类似 Oracle 优化程序中使用的 ORDERED 提示。
SET SHOWPLAN_ALL 和 SET SHOWPLAN_TEXT 语句只返回查询或语句的执行计划信息,但不执行查询或语句。要运行查询或语句,将相应的显示计划语句设为 OFF。然后,查询或语句就会执行。SHOWPLAN 选项与 Oracle EXPLAIN PLAN 工具提供的结果类似。
使用 SET STATISTICES PROFILE ON,每个执行的查询返回标准的结果集,然后,返回附加结果集(给出查询执行的事件探查)。其它选项包括 SET STATISTICS IO 和 SET STATISTIECS TIME。
Transact-SQL 语句处理包括分两步,即编译和执行。NOEXEC 选项编译每个查询,但不执行。NOEXEC 设为 ON 时,不执行随后的语句(包括其它 SET 语句),直到 NOEXEC 设为 OFF 为止。
SET SHOWPLAN ON
SET NOEXEC ON
go
SELECT * FROM DEPT_ADMIN.DEPT,
STUDENT_ADMIN.STUDENT
WHERE MAJOR = DEPT
go
STEP 1
The type of query is SETON
STEP 1
The type of query is SETON
STEP 1
The type of query is SELECT
FROM TABLE
DEPT_ADMIN.DEPT
Nested iteration
Table Scan
FROM TABLE
STUDENT_ADMIN.STUDENT
Nested iteration
Table Scan
Oracle 需要使用提示,来调整基于开销的优化程序的操作和性能。Microsoft SQL Server 基于开销的优化程序不需要使用提示,来协助其查询评估过程。但是在某些情况下,确有使用它们的必要。
INDEX = {index_name | index_id} 提示指定了该表使用的索引名或 ID。 index_id 为 0,就会强制一个表扫描,而当 index_id 为 1,则强制使用聚集索引(如存在)。这和 Oracle 中使用的索引提示类似。
如果其列顺序和 ORDER BY 子句匹配,SQL Server FASTFIRSTROW 提示就会指示优化程序使用非聚集索引。这个提示的运行方式和 Oracle FIRST_ROWS 提示类似。
18、异常的处理
Oracle:
l         预定义异常
异常名称
ORACLE错误
说明
CURSOR_ALREADY_OPEN
ORA-6511
试图打开一个已打开的光标
DUP_VAL_ON_INDEX
ORA-0001
试图破坏一个唯一性限制
INVALID_CURSOR
ORA-1001
试图使用一个无效的光标
INVALID_NUMBER
ORA-1722
试图对非数字值进行数字操作
LOGIN_DENIED
ORA-1017
无效的用户名或者口令
NO_DATA_FOUND
ORA-1403
查询未找到数据
NOT_LOGGED_ON
ORA-1012
还未连接就试图数据库操作
PROGRAM_ERROR
ORA-6501
内部错误
ROWTYPE_MISMATCH
ORA-6504
主变量和光标的类型不兼容
STORAGE_ERROR
ORA-6500
内部错误
TIMEOUT_ON_RESOURCE
ORA-0051
发生超时
TOO_MANY_ROWS
ORA-1422
SELECT INTD命令返回的多行
TRANSACTION_BACKED_OUT
ORA-006
由于死锁提交被退回
VALUE_ERROR
ORA-6502
转换或者裁剪错误
ZERO_DIVIDE
ORA-1476
试图被零除
例如:
DECLARE
X  NUMBER;
BEGIN
X:= 'yyyy';--这里有错
EXCEPTION   WHEN VALUE_ERROR THEN
DBMS_OUTPUT.PUT_LINE('EXCEPTION HANDED');
END;
DECLARE
BAD_ROWID  EXCEPTION;
X  ROWID;
PRAGMA EXCEPTION_INIT(BAD_ROWID,-01445);
BEGIN
SELECT  ROWID  INTO  X  FROM  TAB
WHERE  ROWNUM=1;
EXCEPTION WHEN BAD_ROWID THEN
DBMS_OUTPUT.PUT_LINE('CANNOT QUERY ROWID FROM THIS VIEW');
END;
注意:-01445 因为PRAGMA EXCEPTION_INIT命令把这个变量(-01455)连接到
这个ORACLE错误,该语句的语法如下:
PRAGMA EXCEPTION_INIT(exception_name, error_number);
其中error_number是负数,因为错误号被认为负数,当定义错误时记住使用负号
异常不一定必须是oracle返回的系统错误,用户可以在自己的应用程序中创
建可触发及可处理的自定义异常
DECLARE                                   // 定义异常处理
SALARY_CODE VARCHAR2(1);
INVALID_SALARY_CODE  EXCEPTION;        // INVALID_SALARY_CODE 是异常名
BEGIN
SALARY_CODE:='X';
IF SALARY_CODE NOT IN('A', 'B', 'C') THEN
RAISE INVALID_SALARY_CODE;          // 触发异常处理
END IF;
EXCEPTION WHEN INVALID_SALARY_CODE THEN //处理异常
DBMS_OUTPUT.PUT_LINE('INVALID SALARY CODE');
END;

有三种基本的子查询。它们是:
通过无修改的比较运算符引入,并且必须返回单个值。(单列单行)
Oracle :单列单行子查询只能用在Where子句中。
SQL Server: 可以用在任何表达式中。如:
select title_id,qty,convert(float,qty)/convert(float,(select sum(qty) from sales)) from sales
在通过 IN 引入的列表或者由 ANY 或 ALL 修改的比较运算符的列表上进行操作。(单列多行)
Oracle和SQL Server一样:只能用在Where子句中。
多列子查询
SQL Server:分两种情况。一种情况是该子查询用在Where子句中,且使用关键字exists来作为是否存在的条件;另外一种情况是用在FROM子句中,作为一个导出表使用。如:
select * from titles where exists (select title_id,qty from sales)
Oracle:语法如下:
SELECT col,col,…
FROM table
WHERE (col,col,…) IN (SELECT col,col,… FROM table WHERE condition)
分两种情况。一种情况是成对比较的多列子查询,表示多个列同时相等,才称为满足条件,如:
SELECT ename,deptno,sal,comm
FROM emp
WHERE (sal,NVL(comm,-1)) IN
(SELECT sal,NVL(comm,-1) FROM emp WHERE deptno=30);
另外一种情况是非成对比较的多列子查询,表示不是成对相等,但也称为满足条件,如:
SELECT ename,deptno,sal,comm
FROM emp
WHERE sal IN
(SELECT sal FROM emp WHERE deptno=30)
AND  NVL(comm,-1) IN
(SELECT NVL(comm,-1) FROM emp WHERE deptno=30);
另外,还可以在FROM子句中使用子查询。
、其它语法的比较
Oracle 使用 FOR UPDATE 子句来锁定 SELECT 命令中指定的行。不需要在 Microsoft SQL Server 中使用对等的子句,因为这是默认行为。
SQL Server  COMPUTE 子句用于生成行合计函数(SUM、AVG、MIN、MAX 和 COUNT),它们在查询结果中作为附加行出现。它允许查看一组结果的详细和汇总信息行。可以计算子组的汇总值,以及计算同一组的多个合计函数。
Oracle  SELECT 命令语法不支持 COMPUTE 子句。但是,SQL Server  COMPUTE 子句与 Oracle SQL*Plus 查询工具中的 COMPUTE 命令作用相似。
SQL Server 使用 text 和 image 列,来实现二进制大型对象 (BLOB)。Oracle 使用 LONG 和 LONG RAW 列实现 BLOB。
在 Oracle 中,SELECT 命令可以查询 LONG 和 LONG RAW 列中的值。 在 SQL Server 中,可以使用标准的 T-SQL 语句或专门的 READTEXT 语句读取 text 和 image 列中的数据,READTEXT 语句允许读取 text 或 image 列的部分片段。Oracle 没有提供处理 LONG 和 LONG RAW 部分片段的对等语句。
在 Oracle 中,UPDATE 和 INSERT 命令用于更改 LONG 和 LONG RAW 列中的值。在 SQL Server 中,可以使用标准的 UPDATE 和 INSERT 语句,也可以使用 UPDATETEXT 和 WRITETEXT 语句。UPDATETEXT 和 WRITETEXT 均允许无日志记录的选项,并且 UPDATETEXT 允许对 text 或 image 列进行部分更新。
Oracle  DECODE 语句和 Microsoft SQL Server CASE 表达式都执行条件测试。当 test_value 中的值符合下列任何表达式时,就会返回相关的值。如果不符合,则返回 default_value。如果没有指定 default_value,且不符合任何表达式,则 DECODE 和 CASE 返回 NULL。下面给出了语法以及一个转换的 DECODE 命令的示例。 注意:Oracle9i中也有CASE语句。
DECODE(AA﹐V1﹐R1﹐V2﹐R2....)函数
解释:
IF AA=V1  THEN  RETURN  R1
IF AA=V2  THEN  RETURN  R2
.. .. ..
ELSE
RETURN  NULL
Oracle
CREATE   VIEW    PA(SSN, GPA)
AS SELECT SSN, ROUND(AVG(DECODE(grade,'A', 4,'A+', 4.3,'A-', 3.7)),2)   FROM
STUDENT GROUP BY SSN  ----也可使用CASE语句
Microsoft SQL Server
CREATE    VIEW   PA(SSN, GPA)
AS SELECT SSN, ROUND(AVG(CASE grade
WHEN 'A' THEN 4 WHEN 'A+' THEN 4.3 WHEN 'A-' THEN 3.7 ELSE 0 END),2) FROM
STUDENT GROUP BY SSN
CASE 表达式可以支持使用 SELECT 语句进行布尔测试,这是 DECODE 命令所不允许的。
Oracle函数的一个实例
函数可以接受多个变量而只能返回一个值。
create or replace function get_dob(ss_num varchar2)  return date
as
birthd date; -- 局部日期域存放生日
begin
begin
select dob
into birthd -- 对隐式游标必须用"into"
from person where soc_sec_num = ss_num;
exception
when no_data_found then
begin
error_notify(ss_num); -- 调用其他过程
birthd := trunc(sysdate);
end
when others then  null;
end ;
return birthd;
end;         -- 结束外部块
/            --"/" 结束PL/SQL块
在下面的示例中,Oracle 用户定义的函数 GET_SUM_MAJOR 用于获取按专业 (major) 交纳的学费总和。在 SQL Server 中,可通过把查询作为表使用,以替代这一函数。
Oracle
Microsoft SQL Server
SELECT SSN, FNAME, LNAME,T_PAID,
T_PAID/GET_SUM_MAJOR(MAJOR)
AS P_MAJOR FROM S_A.ST
SELECT  SSN, FNAME, LNAME,T_PAID,
T_PAID/SUM_MAJOR AS P_MAJOR
FROM S_A.ST,(SELECT MAJOR,SUM(T_PAID)
SUM_MAJOR FROM S_A.ST GROUP BY MAJOR)
SUM_ST
WHERE ST.MAJOR = SUM_ST.MAJOR
CREATE  OR  REPLACE  FUNCTION
GET_SUM_MAJOR (IR VARCHAR2)
RETURN NUMBER
AS SUM_PAID NUMBER;
BEGIN
SELECT SUM(T_PAID) INTO SUM_PAID
FROM S_A.ST WHERE MAJOR = IR;
RETURN(SUM_PAID);
END GET_SUM_MAJOR;
不需要 CREATE FUNCTION 语法;使用 CREATE PROCEDURE 语法。
SQL Server LIKE 关键字提供了一些 Oracle 不支持的、有用的通配符搜索选项。除了支持两个 RDBMS 通用的 % 和 _ 通配符外,SQL Server 还支持 [] 和 [^] 字符。
[] 字符用于在给定范围内搜索某一单个字符。例如,如果在单字符位置搜索从 a 到 f 的字符,可以用 LIKE '[a-f]' 或 LIKE '[abcdef]' 指定。此表给出了这些附加通配符的用法。
Oracle
Microsoft SQL Server
SELECT  *  FROM  STUDENT
WHERE  LNAME  LIKE  'A%'
OR  LNAME LIKE 'B%'
OR  LNAME LIKE 'C%'
SELECT  *  FROM  STUDENT
WHERE  LNAME  LIKE '[ABC]%'
[^] 通配符集合用于指定不在给定范围内的字符。例如,如果接受除 a 到 f 以外的任何字符,则使用 LIKE '[^a - f]' 或 LIKE '[^abcdef]'。
以下是每种 RDBMS 支持的关键字。
语句
Oracle PL/SQL
Microsoft SQL Server
Transact-SQL
声明变量
DECLARE
DECLARE
语句块
BEGIN...END;
BEGIN...END
条件处理
IF  THEN,
ELSIF THEN,
ELSE
ENDIF;
IF [BEGIN END]
ELSE
[BEGIN END]
ELSE IF
CASE expression
无条件退出
RETURN
RETURN
无条件退出到当前程序块结束后紧接着的那条语句
EXIT
BREAK
重新开始一个 WHILE 循环
暂缺
CONTINUE
等待指定的间隔
暂缺 (dbms_lock.sleep)
WAITFOR
循环控制
WHILE LOOP END LOOP;
LABEL GOTO LABEL;
FOR END LOOP;
LOOP END LOOP;
WHILE
BEGIN END
LABEL GOTO LABEL
程序注释
/*  */, --
/*  */, --
打印输出
RDBMS_OUTPUT.PUT_LINE
PRINT
提出程序错误
RAISE_APPLICATION_
ERROR
RAISERROR
执行程序
EXECUTE
EXECUTE
语句终止符
分号 (;)
暂缺
Transact-SQL 和 PL/SQL 变量是使用 DECLARE 关键字来创建的。Transact-SQL 变量用 @ 来标识,并且像 PL/SQL 变量一样,第一次创建时该变量被初始化为空值。
Oracle
Microsoft SQL Server
DECLARE
VSSN CHAR(9);
VFNAME VARCHAR2(12);
VLNAME VARCHAR2(20);
VBIRTH_DATE DATE;
VLOAN_AMOUNT NUMBER(12,2);
DECLARE
@VSSN CHAR(9),
@VFNAME VARCHAR2(12),
@VLNAME VARCHAR2(20),
@VBIRTH_DATE DATETIME,
@VLOAN_AMOUNT NUMERIC(12,2)
Transact-SQL 不支持 %TYPE 和 %ROWTYPE 变量数据类型定义。在 DECLARE 命令中,不能对 Transact-SQL 变量进行初始化。Oracle NOT NULL 和 CONSTANT 关键字不能用在 Microsoft SQL Server 数据类型定义中。
与 Oracle LONG 和 LONG RAW 数据类型一样,text 和 image 数据类型不能用于变量声明。此外,不支持 PL/SQL 类型的记录和表定义。
Microsoft SQL Server 赋值语句用set或select,Oracle赋值语句用pascal的语法:=
Oracle
Microsoft SQL Server
赋值运算符 (:=)
SET @local_variable = value
用于从一行中选择列值的
SELECT...INTO 语法。
SELECT @local_variable = expression [FROM] 用于为字面值、涉及其它局部变量的表达式或一行中的列值赋值。
FETCH INTO 语法
FETCH INTO 语法
以下是一些语法示例。
Oracle
Microsoft SQL Server
DECLARE  VSSN CHAR(9);
VFNAME  VARCHAR2(12);
VLNAME  VARCHAR2(20);
BEGIN
VSSN := '123448887';
SELECT FNAME, LNAME INTO
VFNAME, VLNAME FROM
STUDENTS  WHERE SSN=VSSN;
END;
DECLARE  @VSSN CHAR(9),
@VFNAME VARCHAR(12),
@VLNAME VARCHAR(20)
SET  @VSSN = '12355887'
SELECT  @VFNAME=FNAME,
@VLNAME=LNAME FROM STUDENTS
WHERE  SSN = @VSSN
Oracle PL/SQL 和 Microsoft  SQL Server T-SQL 支持使用 BEGIN… END 术语,来指定程序块。T-SQL 不要求在 DECLARE 语句后面使用语句块。在 Microsoft SQL Server 中,如果 IF 语句和 WHILE 循环执行不止一个语句,需要使用 BEGIN…END 语句块。 Oracle的示例如下:
DECLARE       /*声明部分。所有的变量、游标和类型都在这里声明。*/
i NUMBER:=6;
a VARCHAR2(30);
BEGIN  /*执行部分*/
////////////
EXCEPTION     /*异常处理部分*/
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE();
END;
SQL Server T-SQL  IF 条件语句同 Oracle  PL/SQL 中的IF 语句基本相同。对等的CASE 语句如下:
Oracle
Microsoft SQL Server
DECLARE
VD CHAR(1); VD_N VARCHAR2(20);
BEGIN
VDEGREE := 'U';
CASE VD
WHEN 'U' THEN VD_N:='Undergraduate';
WHEN 'M' THEN VD_N:='Masters';
WHEN 'P' THEN VD_N:='PhD';
ELSE VD_N:='Unknown';
END CASE;
END;
DECLARE
@VD CHAR(1), @VD_N VARCHAR(20)
SELECT @VD = 'U'
SELECT @VD_N =
CASE @VD
WHEN 'U' THEN 'Undergraduate'
WHEN 'M' THEN 'Masters'
WHEN 'P' THEN 'PhD'.
ELSE 'Unknown'
END
SQL Server T-SQL 循环语句同 Oracle  PL/SQL 中的循环语句基本相同。Oracle多了一种FOR循环。对等的WHILE语句如下:
Oracle
Microsoft SQL Server
DECLARE
COUNTER NUMBER;
BEGIN
COUNTER := 0
WHILE (COUNTER <5) LOOP
COUNTER := COUNTER + 1;
END LOOP;
END;
DECLARE
@COUNTER NUMERIC
SELECT  @COUNTER = 1
WHILE (@COUNTER <5)
BEGIN
SELECT @COUNTER = @COUNTER +1
END
Transact-SQL可以使用 BREAK 和 CONTINUE 关键字,从循环的内部控制语句的执行。BREAK 关键字导致从 WHILE 循环中无条件退出,CONTINUE 关键字使 WHILE 循环跳过后面的语句,并重新开始循环。BREAK 关键字和 Oracle PL/SQL EXIT 关键字等同。Oracle 没有 CONTINUE 的对等关键字。
Oracle 和 Microsoft SQL Server 均有 GOTO 语句,但是语法不同。遇到 GOTO 语句,Transact-SQL 批处理执行就会跳到标号处。GOTO 语句和标号之间的语句不执行。
Oracle
Microsoft SQL Server
GOTO label;
<