四、Oracle中新的数据库对象:
实例化视图、快照、序列、程序包、同义词、抽象的数据类型
● 实例化视图又称显形图:实例化说明它有自己的存储空间,视图说明它的数据来源于其它表数据。实例化视图中的数据,设置为隔一段时间更新数据,更新的模式可以定义为完全更新和增量更新
● 快照基本上同实例化视图,只不过数据来源不同,快照数据来源于远程数据库,而实例化视图则来源于本地数据表
● 序列,相当于MS SQL 中的identity列,它是一个数字顺序列表,下面有详细介绍。
● 程序包,它是过程、函数、全局变量的集合,它封装了私有变量、私有过程和私有函数,如:dbms-out包
● 同义词,是对数据库中的对象的别名,同义词可以是全局的也可以是私有的(属于某个用户的)如:Tab、col等
● 抽象的数据类型,类似于C中的结构体或Pascal记录类型。
五、Oracle回滚段和SQL Server的数据库事务日志文件
回滚段提供了事物回滚需要使用的数据变化以前的映象,这些映象是按条目存储的,如果这些条目过少,一个事务等待另一个事务的几率增大,就会影响数据库的性能。缺省安装时,提供一个系统回滚段,它在system表空间。为了提高性能,system表空间不应存储有任何数据字典信息以外的信息。每次启动时,Oracle RDBMS 执行自动恢复。它检验表空间文件的内容是否与联机重做日志文件一致。如果不一致,Oracle 将联机重做日志文件内容应用到表空间文件(前滚),并删除回滚段中发现的任何未提交的事务(回滚)。如果 Oracle 不能从联机重做日志文件中得到它所需要的信息,它就会查询存档重做日志文件。
每个 SQL Server 事务日志均有 Oracle 回滚段与 Oracle 联机重做日志的组合功能。每个数据库都有自已的事务日志,它记录了对数据库所作的全部更改,并且由数据库的所有用户共享。当一个事务开始且发生数据修改时,就会在日志中记录一个 BEGIN TRANSACTION 事件(以及修改事件)。在自动故障恢复过程中,这个事件用于确定事务的起始点。在收到每个数据修改语句时,先将更改写入事务日志,然后再写入数据库。MS SQL 数据库事务日志文件功能雷同于回滚段,只不过它是同特定的数据库密切相关的。
六、主要数据类型的对比
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><!-- saved from url=(0033)http://www.oradb.net/datatype.htm -->
<BIG>ORACLE的数据类型</BIG>
常用的数据库字段类型如下:
<TBODY>字段类型 |
中文说明 |
限制条件 |
其它说明 |
<SMALL>CHAR</SMALL> |
<SMALL>固定长度字符串</SMALL> |
<SMALL>最大长度2000 bytes </SMALL> |
|
<SMALL>VARCHAR2</SMALL> |
<SMALL>可变长度的字符串</SMALL> |
<SMALL>最大长度4000 bytes </SMALL> |
<SMALL>可做索引的最大长度749</SMALL> |
<SMALL>NCHAR</SMALL> |
<SMALL>根据字符集而定的固定长度字符串</SMALL> |
<SMALL>最大长度2000 bytes </SMALL> |
|
<SMALL>NVARCHAR2</SMALL> |
<SMALL>根据字符集而定的可变长度字符串</SMALL> |
<SMALL>最大长度4000 bytes </SMALL> |
|
<SMALL>DATE</SMALL> |
<SMALL>日期(日-月-年)</SMALL> |
<SMALL>DD-MM-YY(HH-MI-SS)</SMALL> |
<SMALL> </SMALL> |
<SMALL>LONG</SMALL> |
可变长度的字符数据</SMALL> |
<SMALL>最大长度</SMALL>2G(231-1) |
足够存储大部头著作 |
<SMALL>RAW</SMALL> |
<SMALL>固定长度二进制数据</SMALL> |
<SMALL>最大长度2000 bytes </SMALL> |
<SMALL>可存放比较小的多媒体图象声音等</SMALL> |
<SMALL>LONG RAW</SMALL> |
<SMALL>可变长度的二进制数据</SMALL> |
<SMALL>最大长度</SMALL>2G |
<SMALL>可存放比较大的多媒体图象声音等</SMALL> |
<SMALL>BLOB</SMALL> |
大型的<SMALL>二进制对象(可变长度)</SMALL> |
<SMALL>最大长度</SMALL>4G
|
1、 一个表可有多个这 种列 2、使用select语句只能返回存储这种数据的位置 3、既可联机存储,也可脱机存储 4、支持对象(Object)类型 5、随机访问数据 |
<SMALL>CLOB</SMALL> |
大型的CHAR类型数据</SMALL> |
||
<SMALL>NCLOB</SMALL> |
大型的<SMALL>NCHAR类型数据</SMALL> |
||
<SMALL>BFILE</SMALL> |
<SMALL>存放在数据库外的大型的二进制文件</SMALL> |
||
<SMALL>ROWID</SMALL> |
<SMALL>数据表中记录的唯一行号</SMALL> |
<SMALL>10 bytes ********.****.****格式,*为0或1,存储在索引中。</SMALL> |
|
UROWID <SMALL></SMALL> |
同上<SMALL> </SMALL> |
存储在索引中<SMALL> </SMALL> |
|
NROWID |
二进制数据表中记录的唯一行号 |
最大长度4000 bytes |
|
<SMALL>NUMBER(P,S)</SMALL> |
<SMALL>数字类型</SMALL> |
<SMALL>P为总的位数,S为小数位</SMALL> |
|
<SMALL>DECIMAL(P,S)</SMALL> |
<SMALL>数字类型</SMALL> |
<SMALL>P为总的位数,S为小数位</SMALL> |
|
<SMALL>INTEGER</SMALL> |
<SMALL>整数类型</SMALL> |
小的整数 |
|
<SMALL>FLOAT</SMALL> |
<SMALL>浮点数类型</SMALL> |
<SMALL>NUMBER(38),双精度</SMALL> |
|
<SMALL>REAL</SMALL> |
<SMALL>实数类型</SMALL> |
<SMALL>NUMBER(63),精度更高</SMALL></TBODY> |
<SMALL>
注意:每个表中只能有一个LONG或LONG RAW列,……….。</SMALL>
<SMALL> <SMALL> </SMALL>
<SMALL> 二者映射关系: From SQL Server To Oracle
</SMALL>
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 |
varchar 或 text。(如果 Oracle 列中数据值的长度为 8000 字节或更少,则使用 varchar;否则,必须使用 text。) |
RAW 和 |
varbinary 或 image。(如果 Oracle 列中数据值的长度为 8000 字节或更少,则使用 varbinary;否则,必须使用 image。) |
NUMBER |
如果整数在 1 和 255 之间,使用 tinyint。 |
ROWID |
使用 identity 列类型。 |
CURRVAL, NEXTVAL |
使用 identity 列类型以及 @@IDENTITY、IDENT_SEED() 和 IDENT_INCR() 函数。 |
七、语法上的区别
1、基本SQL语句的区别
l SELECT 语句
l SQL Server 不支持 Oracle 的 INTERSECT 和 MINUS 集合运算符。可使用 SQL Server EXISTS 和 NOT EXISTS 子句,实现相同的结果。
下面两条语句返回的数据是相同的。
Oracle(返回两个查询都有的行) |
Microsoft SQL Server |
SELECT CCODE, CNAME |
SELECT CCODE, CNAME STUDENT G |
下面两条语句返回的数据是相同的。
Oracle |
Microsoft SQL Server |
SELECT CCODE, CNAME |
SELECT CCODE, CNAME STUDENT G |
l 将 SELECT 语句做为表名使用
Microsoft SQL Server 和 Oracle 均支持在执行查询时,把 SELECT 语句作为表的来源使用。SQL Server 需要一个别名;Oracle别名的使用是可选的。
Oracle |
Microsoft SQL Server |
SELECT SSN,LNAME,SUM_PAID SUM_PAID FROM STUDENT) |
SELECT SSN, LNAME,SUM_PAID 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) |
INSERT INTO GRADE (SSN, CCODE, GRADE) |
Transact-SQL values_list 参数提供了 SQL-92 标准关键字 DEFAULT,但 Oracle 不支持。此关键字指定了执行插入操作时使用列的默认值。如果指定列的默认值不存在,则插入 NULL。如果该列不允许 NULL,则返回一个错误消息。如果该列数据类型定义为 timestamp,则插入下一个有序值。
l DELETE 语句
如果要对 Oracle 中的 SELECT 语句执行删除操作,则必须修改 SQL Server 语法,因为 Transact-SQL 不支持这一功能。 Transact-SQL 支持在 WHERE 子句中使用子查询,以及在 FROM 子句中使用联接。后者可产生更有效的语句。请参见后面“UPDATE 语句”中的示例。
Oracle |
Microsoft SQL Server |
DELETE [FROM] |
DELETE |
注意:删除记录并不能释放ORACLE里被占用的数据块表空间. 它只把那些被删除的数据块标成unused.如果确实要删除一个大表里的全部记录, 可以用 TRUNCATE 命令, 它可以释放占用的数据块表空间 TRUNCATE TABLE 表名,但此操作不可回退。
l EXISTS
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、表数据复制
l 库内数据复制
MS SQL Server
Insert into 复制表名称 select语句 (复制表已存在)
Select 字段列表 into 复制表名称 from 表(复制表不存在)
Oracle
Insert into 复制表名称 select语句(复制表已存在)
create table 复制表名称 as select语句(复制表不存在)
l 文本文件转入、转出的批量处理
MS SQL Server
BCP命令行程序
Oracle
SQLLDR命令行程序
3、表数据更新
l 根据其它表数据更新你要更新的表。
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 |
DECLARE |
在 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 AND G.CCODE = '1234') |
Subquery: FROM GRADE G WHERE G.SSN = S.SSN AND G.CCODE = '1234') |
4、内联结,外联结, 交叉联接
MS SQL Server
- 内联接 仅显示两个联接表中的匹配行的联接。(这是查询设计器中的默认联接类型。)例如,可以联接
titles
表和publishers
表以创建显示每个书名的出版商名称的结果集。在内联接中,结果集内不包含没有出版商信息的书名,也不包含没有书名的出版商。如:
SELECT title, pub_name FROM titles INNER JOIN
publishers ON titles.pub_id = publishers.pub_id
注意 当创建内联接时,包含 NULL 的列不与任何值匹配,因此不包括在结果集内。空值不与其它的空值匹配。
内联结也就是我们平常的等联结.在SQL-92标准之中,内部联结可指定于FROM或WHERE子句中.这是 SQL-92在WHERE子句中唯一支持的联结类型.
- 外联接 甚至包括在联接表中没有相关行的行的联接。可以创建外联接的三个变化形式来指定所包括的不匹配行:
- 左向外联接 包括第一个命名表("左"表,出现在 JOIN 子句的最左边)中的所有行。不包括右表中的不匹配行。例如,下面的 SQL 语句说明
titles
表和publishers
表之间的左向外联接包括所有的书名,甚至包括那些没有出版商信息的书名:
- 左向外联接 包括第一个命名表("左"表,出现在 JOIN 子句的最左边)中的所有行。不包括右表中的不匹配行。例如,下面的 SQL 语句说明
SELECT titles.title_id, titles.title, publishers.pub_name
FROM titles LEFT OUTER JOIN publishers ON titles.pub_id
= publishers.pub_id
- 右向外联接 包括第二个命名表("右"表,出现在 JOIN 子句的最右边)中的所有行。不包括左表中的不匹配行。例如,在
titles
和publishers
表之间的右向外联接将包括所有的出版商,甚至包括那些在titles
表中没有书名的出版商。如:
SELECT titles.title_id, titles.title, publishers.pub_name
FROM titles RIGHT OUTER JOIN publishers ON titles.pub_id
= publishers.pub_id
- 完整外部联接 包括所有联接表中的所有行,不论它们是否匹配。例如,
titles
表和publishers
表之间的完整外部联接显示所有书名和所有出版商,甚至包括那些在另一个表中没有匹配值的书名和出版商。
SELECT titles.title_id, titles.title, publishers.pub_name
FROM 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);
5、存储过程或函数中使用的临时表
这是Oracle 明显不如SQL Server的一个地方。
l 临时表的处理机制
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最让人不满意的是它必须优化!”过了一个季度甚至于一个月,我们的用户就会向我们抱怨我们的系统跑得越来越慢了.又提到了我前面说过的话:我们的绝大多数程序没有受到真正的考验,如果不考虑清楚的话,我们的系统将有严重的问题.
l SQL Server中的临时表移植到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字段。每个连接只处理本连接的数据。
l 下面两条语句效果相当(全局临时表):
MS SQL Server
Create table ##表名 或 select into ##表名
Oracle
CREATE GLOBAL TEMPORARY TABLE temp1
(……
sessionid int)
on commit delete rows;
6、分组语句 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 子句中的列
7、存储过程
l Oracle的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;
/
l 在Oracle的sp中不能出现DDL语句.
因为所有的DDL语句(create,drop,alter,truncate等)都是显式带有commit命令,Oracle的sp中不能有显式commit的存在。如果你非要在sp中建表或者删除表的话,你可以用动态SQL来完成隐式commit。因此下面的语句在sp中是错误的:
1、Create table 表名
2、Drop table 表名
l 延迟存储过程的执行
Microsoft SQL Server 提供了 WAITFOR,它允许开发人员指定触发语句块、存储过程或事务执行的时间、时间间隔或事件。它相当于 Oracle 的 dbms_lock.sleep。
l SQL Server 的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;
/
l 临时存储过程
在 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; |
CREATE PROCEDURE S_R_S SELECT FNAME+LNAME+SSN FROM STUDENT S |
EXCEPTION |
|
8、触发器
l 功能上的对比
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
l 将SQL Server的触发器移植至Oracle上
将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;
9、视图
在 Microsoft SQL Server 中,用于创建视图的语法与 Oracle 相似。
Oracle |
Microsoft SQL Server |
CREATE [OR REPLACE] [FORCE | |
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) |
CREATE VIEW S_A.SGPA(SSN, GPA) |
10、关于游标
l 游标的简单定义
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子串,只有一行数据被处理 |
可以处理多行数据,在程序中设置循环,取出每一行数据。 |
来源:https://www.cnblogs.com/cxd4321/archive/2008/04/14/1153156.html