??xml version="1.0" encoding="utf-8" standalone="yes"?>
参? http://otl.sourceforge.net/otl3_stream_class.htm
50 2.06
<1:536704> 18:31:58.068 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:536704> 18:34:04.713 [00001] There are 3612066 records is loaded!
100 1.38
<1:2085112> 18:36:23.727 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:2085112> 18:38:01.923 [00001] There are 3612066 records is loaded!
1.23
<1:2085112> 18:38:06.941 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:2085112> 18:39:29.849 [00001] There are 3612066 records is loaded!
200 1.02
<1:1499250> 18:41:47.711 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:1499250> 18:42:49.300 [00001] There are 3612066 records is loaded!
<1:1499250> 18:42:54.312 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:1499250> 18:43:53.717 [00001] There are 3612066 records is loaded!
500 0.43
<1:1978536> 18:45:57.790 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:1978536> 18:46:40.685 [00001] There are 3612066 records is loaded!
<1:1978536> 18:45:09.982 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:1978536> 18:45:52.787 [00001] There are 3612066 records is loaded!
1000 0.35
<1:1597632> 18:47:42.973 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:1597632> 18:48:17.715 [00001] There are 3612066 records is loaded!
<1:1597632> 18:48:22.718 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:1597632> 18:49:01.119 [00001] There are 3612066 records is loaded!
<1:1597632> 18:51:17.837 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:1597632> 18:51:24.416 [10001] Signal 31 recieved.
<1:1597632> 18:49:49.976 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:1597632> 18:50:28.192 [00001] There are 3612066 records is loaded!
2000 0.34
<1:2883830> 18:51:47.365 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:2883830> 18:52:21.163 [00001] There are 3612066 records is loaded!
<1:2883830> 18:52:26.166 [00001] The load SQL is [select USER_NUMBER from dr_gsm_931_20050831 where 1=1 ]
<1:2883830> 18:53:01.576 [00001] There are 3612066 records is loaded!
当异常生成之后,E序被中止,控制权交l异常处理模块,异常处理模块捕获当前异常句柄Qƈ交由相应的程序处理;如果Q异怿里模块没有捕捉到异常句柄Q那么它被传输到当前程序的外围?/span>
除非׃些特D的要求Q一般情况下异常再当前E序的异常处理模块中被处理。异常处理模块以 EXCEPTION 开?/span> END; l尾?/span>
Declare
/*………?/
begin
/*………?/
exception
when /* 异常名称 */
then /* 异常处理 */
when other
then /* 异常处理 */
end;
异常处理模块的语法基本上?/span> CASE 一_凡是?/span> when 中有定义的异帔R被处理Q而没有的则被传输。一个特D的异常处理语句?/span> WHEN OTHERS 。就惛_Q?/span> 3 Q中所说的Q它会处理所有ؓ被处理的异常Q因此必d心用它Q最好是在最外层的程序中。当然如果喜Ƣ偷懒的Q大可以在异常处理模块中只放一?/span> OTHERS 。注意,无论哪种情况Q?/span> OTHERS 只能q只在异常处理的最后一位?/span>
有趣的是Q可以在一?/span> when 中处理多个异常句柄?/span>
Exception
When no_data_found or invalid_employee_id or dbms_ldap.invalid session
Then /*……?.*/
End;
/
在这个例子里Q有标准包的异常、自定义异常和非标准包中的异常。这些异常只能用 or q接Q不可以?/span> and Q因为只有一个异常能够生成?/span>
?/span> raise_application_error 生成的异常,如果没有被处理而一直传递到pȝ环境中,那么环境视情况作出相应的反映。在 sqlplus 中, oracle 回滚所?/span> DML Ҏ据所做的修改。在 sqlplus 环境中,因ؓ有自动回滚的存在Q我们可以保留出现未被处理的异常的可能性;而在另外的一些环境中Q则需要仔l设计最外层E序?/span>
ü 捕捉M有可能传出的异常?/span>
ü 记录错误以便于分析?/span>
ü l外部环境一个信息,以便于其作出相应的处理?/span>
对于自定义异常,因ؓ sqlcode 值永q是 1 Q所以当它被传出Ӟ如果外围E序中没有定义相同名U的异常Q我们将不知道是什么异生了。因此,不要自定义异常传递出厅R?/span>
在程序中处理几个互相独立的操作时Qؓ了避免出现因Z个操作生异常而整个E序被中断的情况Q有必要这些独立的操作攑֜各自的虚拟块中?/span>
Procedure change_data is
Begin
Begin
Delete from employee where ?.
Exception
When others then null;
End;
Begin
Update company set …?
Exception
When others then null;
End;
Begin
Insert into company_history select * from company where ?
Exception
When others then null;
End;
End;
/
Pl/sql
提供了一些内建的函数来帮助我们确定、分析异常?/span>
SQLCODE
q个函数在前面有提到q,它是一个用于返回当前模块中最q一ơ异常值的函数Q或者说是非入栈E序的异常倹{打个比方:如果在当前程序的异常模块中调用了另一个程序, oracle 当前程序及相应的环境变量(包括异常|压入pȝ栈;在被调用E序中生成了一个gؓ 1 的异常,那么 sqlcode 返?/span> 1 Q之后刚才的E序出栈Q?/span> sqlcode q回当前异常倹{需要注意的是,不要在异常模块之外用它Q这样不会有M意义。当没有异常或在异常模块之外使用Ӟ SQLCODE q回 0 Q返回?/span> 1 是指自定义异常?/span>
SQLERRM
接收异常|q回相应的长度不过 512 字节的描q语。如果没有传入异常|则返回当前异常描q?/span>
Begin
Dbms_output.put_line( sqlerrm(-1403);
End;
Sql>/
Ora-1403: no data found
在需要体构长度超q?/span> 512 字节的描q时Q?/span> oracle 使用 dbms_utility.format_error_stack 。显Ӟ用这个函数来判断一个异常是否ؓpȝ异常是很有用的,如果不是的话Q将q回以下两种情况的一U?/span>
如果是一个负敎ͼ
ora-nnnnn: message not found,; product=rdbms; facility=ora
如果是一个正敎ͼ
-nnnnn: non-oracle exception
DBMS_UTILITY.FORMAT_ERROR_STACK
q回当前异常相应的描qͼ没有字符长度限制。与 SQLCODE 相同的是Q必d异常处理模块中用。虽然名UC有一?/span> stack 在,但通过它ƈ不能知道异常的最初生成处Q需要的话就必须使用 DBMS_UTILITY.FORMAT_ERROR_BACKTRACE ?/span>
DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
pȝ为最q一ơ生成的异常讄了一个栈Qƈ跟踪它的传递过E,而这个函C用这个栈Q然后返回该异常的整个传递过E。这个函数对错误的定位和实施下一步处理v着臛_重要的作用?/span>
Create or replace procedure procl is
Begin
Dbms_output.put_line(‘running proc1?;
Raise no_data_found;
End;
/
create or replace procedure proc2 is
begin
dbms_output.put_line(‘calling proc1?;
proc1;
end;
/
create or replace procedure proc3 is
begin
dbms_output.put_line(‘calling proc2?;
proc2;
exception
when no_data_found
then
dbms_output.put_line(‘error stack at top level?;
dbms_output.put_line(dbms_utility.format_error_backtrace);
end;
/
现在可以q行 proc3 来看看结果?/span>
Sql>set serveroutput on;
Sql>begin
2 dbms_output.put_line(‘proc3->proc2->proc1 backtrace?;
3 proc3;
4 end;
5 /
Proc3 -> Proc2 -> Proc1 backtrace
calling proc2
calling proc1
running proc1
Error stack at top level:
ORA-06512: at "SCOTT.PROC1", line 4
ORA-06512: at "SCOTT.PROC2", line 5
ORA-06512: at "SCOTT.PROC3", line 4
事实上,每次异常的生都重|这个异常栈Q只是最后一ơ从pȝ栈出栈的是最外层的程序块Q所以可以清楚地看到异常生成的整个过E。上面这个程序的执行q程是这LQ首先用 put_line 打印 Proc3 -> Proc2 -> Proc1 backtrace Q?/span> 调用 proc3 Q当前程序入?/span> => 打印 calling proc2 Q调?/span> proc2 Q?/span> proc3 入栈 => 打印 calling proc1 Q调?/span> proc1 Q?/span> proc2 入栈 => 打印 running proc1 Q生?/span> no_data_found 异常Q该异常被压入异常栈?/span> => proc2 出栈Qƈ到来自W?/span> 5 行调用传递过来的异常Q将它在此压入异常栈 => proc3 出栈Qƈ到来自W?/span> 4 行调用传递过来的异常Q将它在此压入异常栈Q?/span> dbms_utility.format_error_backtrace 异常栈中信息反相打印出?/span> => 最外层E序出栈Q?/span> end ?/span>
以下是正用这个函数的一些注意事:
ü 在当前程序的异常处理模块中调用这个函数?/span>
ü 避免在中间程序中使用异常处理模块?/span>
q样异常p被正地传输到最外层E序中,q打印出q个q程了?/span>
l Raise exception;
l Raise package.exception;
l Raise;
以上?/span> raise 的三U用方法。第一U用于生成当前程序中定义的异常或?/span> standard 中的pȝ异常?/span>
Declare
Invalid_id exception;
Id_values varchar(2);
Begin
Id_value:=id_for(‘smith?;
If substr(id_value,1,1)!=’x?/span>
Then
Raise invalid_id;
End if;
Exception
When invalid_id
Then
Dbms_output.put_line(‘this is an invalid id!?;
End;
q是一个生成自定义异常的例子,当然也可以生成系l异常:
declare
employee_id_in number;
Begin
Select employee_id into employee_id_in from employ_list where employee_name=&n;
If employee_id_in=0
Then
Raise zero_devided;
End if;
Exception
When zero_devided
Then
Dbms_output.put_line(‘wrong!?;
End;
有一些异常是定义在非标准包中的,?/span> UTL_FILE Q?/span> DBMS_SQL 以及E序员创建的包中异常。可以?/span> raise 的第二种用法来生成异常?/span>
If day_overdue(isbn_in, browser_in) > 365
Then
Raise overdue_pkg.book_is_lost
End if;
在最后一U?/span> raise 的Ş式中Q不带Q何参数。这U情况只出现在希望将当前的异怼到外部程序时?/span>
Exception
When no_data_found
Then
Raise;
End;
Pl.sql 使用 raise_application_error q程来生成一个有具体描述的异常。当使用q个q程Ӟ当前E序被中止,输入输出参数被置为原先的|但Q?/span> DML Ҏ据库所做的改动被保留Q可以在之后?/span> rollback 命o回滚。下面是该过E的原型Q?/span>
Procedure raise_application_error(
Num binary_integer;
Msg varchar2;
Keeperrorstack Boolean default false
)
其中 num 是在 -20999 ?/span> -20000 之间的Q何数字(但事实上Q?/span> DBMS_OUPUT ?/span> DBMS_DESCRIBLE 包用了 -20005 ?/span> -20000 的数字)Q?/span> msg 是小?/span> 2K 个字W的描述语,M大于 2K 的字W都被自动丢弃Q?/span> keeperrorstack 默认?/span> false Q是指清I异常栈Q再当前异常入栈,如果指定 true 的话q接将当前异常压入栈中?/span>
CREATE OR REPLACE PROCEDURE raise_by_language (code_in IN PLS_INTEGER)
IS
l_message error_table.error_string%TYPE;
BEGIN
SELECT error_string
INTO l_message
FROM error_table, v$nls_parameters v
WHERE error_number = code_in
AND string_language = v.VALUE
AND v.parameter = 'NLS_LANGUAGE';
RAISE_APPLICATION_ERROR (code_in, l_message);
END;
异常定义
在一个异生、被捕获q处理之前,它必被定义?/span> Oracle 定义了几千个异常Q绝大多数只有错误编号和相关描述Q仅仅命名了若干个最常被用到的异常。这些名字被储存?/span> STANDARD Q?/span> UTL_FILE Q?/span> DBMS_SQL q几个系l包中,详情误 oracle:pl/sql 异常处理Q?/span> 1 Q?/span>
之外的绝大多数异帔R要程序员命名。有 2 U命名异常的ҎQ?/span>
1 Q声明一个自定义异常
?/span> STANDARD 中的命名了的异常基本山是与系l的错误相关的(当然那些只有 errorcode 的异怹是这PQ但在实际的应用中我们经帔R要与特定的应用程序相关的异常Q由E序员声明的异常是用于处理q种情况的?/span>
Oracle 异常处理模块的方便的地方在于Q它q没有区别对待自定义的与预定义的异常。这使得我们可以像对待预定义异常一P捕捉和处理自定义异常Q只是在此之前需要声明它Q同时对于一个自定义的异常,我们需要用 RAISE 来手动生?/span>
下面是一个声明的例子Q?/span>
procedure calc_ammul_sales
(company_id_in in company.company_id%tye)
is
invalid_company_id exception;
negative_balance excrption;
duplicate_company Boolean;
begin
/*body of executable statement*/
exception
when invalid_company_id
then /*handle exception*/
when no_data_found
then /*handle exception*/
/*?.*/
end;
需要注意的是处理定义的时候,只有两个地方会出现自定义的异常:
ü raise exception Q?/span>
ü when exception then
2 Qؓ非预定义异常兌一个名?/span>
仅仅 21 个预定义异常Ҏ们来说实在是太少了,q有几千个异常只?/span> errorcode 和描q。另外,E序员也可以?/span> RAISE_APPLICATION_ERROR 定义一个含 errorcode 和描q的异常?/span>
当然Q只?/span> errorcode 也可以很好地完成工作Q只要你不担心会忘了那串数字代表的意思就行。比方说 ;
exception
when others
then
if sqlcode=-1843 then /*sqlcode 是内建的用于q回最q一ơ错误编L函数 */
?.
q的是一D让人感到晦涩的代码Q还是给它关联个名字吧?/span>
我们要用到的?/span> pragma exception_init(exception,integer) Q然后就可以像对待预定义异常一样对待它了,我是说没必要像上面的那种一L raise ?/span> Exception_init 是一个编译时q行的函敎ͼ它只能出现在代码的声明部分,而异常名字必d此之前被定义。下面用一个匿名过ED个例子:
declare
invalid_company_id exception;
pragma exception_init(invalid_company_id, -1834);
要注意的Ӟ
ü 不可以用 -1403 Q?/span> no_data_found Q,?/span> 100 Q事实上 exception_init 中的 integer 对应的是 sqlcode q回的倹{?/span>
ü 不能?/span> 0 Q不能大?/span> 100 Q不能小?/span> -1000000
一个例子:
procedure delete_company(company_id_in in number)
is
still_have_emplyee exception;
pragma exception(still_have_employee, -2293);
begin
delete from compamy
where company_id=company_id_in;
exception
when still_have_employee
then dbms_output.put_line(‘delete employees for company first?;
end;
在一下两U情况下Q我们有必要使用 exception_init Q?/span>
ü 一个非预定义异常是l常要被用到的?/span>
ü 我们用 raise_applocation_error 产生了一个自定义?/span> errorcode 时?/span>
一U简便的Ҏ是将以上两种情况中的异常定义在一个包中,q样我们没有必要每ơ都重复定义了?/span>
Create or replace package dynsql
Is
Invalid_table_name exception;
Pragma exception_init(invalid_table_name, -903);
Invalid_column_name exception;
Pragma exception_init(invalid_column_name, -904);
En_too_young const number:=-200001;
Exc_too_young exception;
Pragma exception_init(exc_too_young, -20001);
End;
有了上面q个包,可以方便的处理异常?/span> ;
procedure validate_emp(birthdate in date)
is
min_tear const pls_integer:=18;
begin
if add_month(sysdate,min_year*12*-1)<birthdate_in
then
raise_application_error(dynsql.en_too_young, ‘employee must be?|| min_year ||‘old?;
end if;
end;
除了 standard 包中?/span> 21 个预定义异常外,q有一些包也定义了一些异常。但?/span> standard 包中异常不同的是Q在使用q些异常Ӟ需要带上包的名字。如Q?/span>
when dbms_lob.invalid_argval then …?/span>
非常有用的一ҎQ可以在最外层?/span> pl/sql 块的异常处理模块中加?/span> others Q这样就可以把从内部传递出来的未被处理的剩余异常全部处理掉了?/span>
Exception
When others
Then ?
隐式游标
|
昑ּ游标
|
PL/SQL
l护Q当执行查询时自动打开和关?/span>
|
在程序中昑ּ定义、打开、关闭,游标有一个名字?/span>
|
游标属性前~?/span>
SQL
|
游标属性的前缀是游标名
|
属?/span>
%ISOPEN
L?/span>
FALSE
|
%ISOPEN
Ҏ游标的状态确定?/span>
|
SELECT
语句带有
INTO
子串Q只有一行数据被处理
|
可以处理多行数据Q在E序中设|@环,取出每一行数据?/span>
|
DECLARE R_emp EMP % ROWTYPE; CURSOR c_emp IS SELECT * FROM emp;
DECLARE CURSOR c_emp IS SELECT ename,salary FROM emp;R_emp c_emp % ROWTYPE;
FOR record_name IN (corsor_name [ (parameter[,parameter ] ...)] | (query_difinition)LOOPstatements END LOOP;
IF condition THEN Statements 1; Statements 2; .... END IF |
IF condition THEN Statements 1; Statements 2; .... ELSE Statements 1; Statements 2; .... END IF |
if (a>b) and (a>c) then g:=a; else g:=b; if c>g then g:=c; end if end if |
IF condition1 THEN statement1; ELSIF condition2 THEN statement2; ELSIF condition3 THEN statement3; ELSE statement4; END IF; statement5; |
X:=100; LOOP X:=X+10; IF X>1000 THEN EXIT; END IF END LOOP; Y:=X; |
X:=100; LOOP X:=X+10; EXIT WHEN X>1000; X:=X+10; END LOOP; Y:=X; |
X:=100; WHILE X<=1000 LOOP X:=X+10; END LOOP; Y=X; |
FOR counter IN [REVERSE] start_range....end_range LOOP statements; END LOOP; |
X:=100; FOR v_counter in 1..10 loop x:=x+10; end loop y:=x; |
Variable_name [CONSTANT] databyte [NOT NULL][:=|DEFAULT expression] |
ZERO_VALUE CONSTANT NUMBER:=0; |
Datatype | Range | Subtypes | description |
BINARY_INTEGER | -214748-2147483647 | NATURAL NATURAL NPOSITIVE POSITIVEN SIGNTYPE | 用于存储单字节整数?br />要求存储长度低于NUMBER倹{?br />用于限制范围的子cd(SUBTYPE): NATURAL:用于非负?br /> POSITIVE:只用于正?br /> NATURALN:只用于非负数和非NULL?br /> POSITIVEN:只用于正敎ͼ不能用于NULL?br /> SIGNTYPE:只有?-1??. |
NUMBER | 1.0E-130-9.99E125 | DEC DECIMAL DOUBLE PRECISION FLOAT INTEGERIC INT NUMERIC REAL SMALLINT | 存储数字|包括整数和QҎ。可以选择_ֺ和刻度方式,语法Q?br />number[Q?precision>[, |
PLS_INTEGER | -2147483647-2147483647 | 与BINARY_INTEGER基本相同Q但采用机器q算ӞPLS_INTEGER提供更好的性能 ?/td> |
datatype | rang | subtype | description |
CHAR | 最大长?2767字节 | CHARACTER | 存储定长字符Ԍ如果长度没有定Q缺省是1 |
LONG | 最大长?147483647字节 | 存储可变长度字符?/td> | |
RAW | 最大长?2767字节 | 用于存储二进制数据和字节字符Ԍ当在两个数据库之间进行传递时QRAW数据不在字符集之间进行{换?/td> | |
LONGRAW | 最大长?147483647 | 与LONG数据cd怼Q同样他也不能在字符集之间进行{换?/td> | |
ROWID | 18个字?/td> | 与数据库ROWID伪列cd相同Q能够存储一个行标示W,可以行标示W看作数据库中每一行的唯一键倹{?/td> | |
VARCHAR2 | 最大长?2767字节 | STRINGVARCHAR | 与VARCHAR数据cd怼Q存储可变长度的字符丌Ӏ声明方法与VARCHAR相同 |
datatype | range | description |
BOOLEAN | TRUE/FALSE | 存储逻辑值TRUE或FALSE,无参?/td> |
DATE | 01/01/4712 BC | 存储固定长的日期和时间|日期g包含旉 |
operator | operation |
+ | ?/td> |
- | ?/td> |
/ | ?/td> |
* | ?/td> |
** | 乘方 |
operator | operation |
< | 于操作W?/td> |
<= | 于或等于操作符 |
> | 大于操作W?/td> |
>= | 大于或等于操作符 |
= | {于操作W? |
!= | 不等于操作符 |
<> | 不等于操作符 |
:= | 赋值操作符 |
operator | operation |
IS NULL | 如果操作CؓNULLq回TRUE |
LIKE | 比较字符串?/td> |
BETWEEN | 验证值是否在范围之内 |
IN | 验证操作数在讑֮的一pdg |
operator | operation |
AND | 两个条g都必L?/td> |
OR | 只要满两个条g中的一?/td> |
NOT | 取反 |
declare v_comm_percent constant number:=10; begin update emp set comm=sal*v_comm_percent where deptno=10; end SQL> / PL/SQL procedure successfully completed. SQL> |
create or replace procedure update_commission (v_dept in number,v_pervent in number default 10) is begin update emp set comm=sal*v_percent where deptno=v_dept; end SQL>/ Procedure created SQL>execute update_commission(10,15); PL/SQL procedure successfully completed. SQL> |
declare v_dept number; begin select a.deptno into v_dept from emp a where job='PRESIDENT' update_commission(v_dept); end SQL>/ PL/SQL procedure successfully completed SQL> |
[DECLARE] ---declaration statements BEGIN ---executable statements [EXCEPTION] ---exception statements END |
FUNCTION name [{parameter[,parameter,...])] RETURN datatypes IS [local declarations] BEGIN execute statements [EXCEPTION exception handlers] END [name] |
PROCEDURE name [(parameter[,parameter,...])] IS [local declarations] BEGIN execute statements [EXCEPTION exception handlers ] END [name] |
先徏序列,然后建立一个触发器实现!
cata0是表?cata0_id是需要自增的字段!
CREATE SEQUENCE SEQ_cata0
INCREMENT BY 1
START WITH 1
MAXVALUE 9999999
CREATE TRIGGER TRG_cata0 BEFORE
INSERT ON cata0
FOR EACH ROW begin
SELECT SEQ_cata0.NEXTVAL
INTO :NEW.cata0_ID
FROM DUAL;
End TRG_cata0;