語法:create [or replace] procedure procedure_name(argument1 [model]datatype1,argment2 [mode2],...)
is [as]
pl/sql block;
1.建立過程:不帶任何引數
create or replace procedure out_time
is
begin
dbms_output.put_line(systimestamp);
end;
2.呼叫過程
set serveroutput on
exec out_time
set serveroutput on
call out_time();
3.建立過程:帶有IN引數
CREATE OR REPLACE PROCEDURE add_employee(eno NUMBER,
NAME VARCHAR2,
sal NUMBER,
job VARCHAR2 DEFAULT 'clerk',
dno NUMBER) IS
e_integrity EXCEPTION;
PRAGMA EXCEPTION_INIT(e_integrity, -2291);
BEGIN
INSERT intoimp
(empno,
ename,
sal,
job,
deptno)
VALUES
(eno,
NAME,
sal,
job,
dno);
EXCEPTION
WHEN dup_val_on_index THEN
raise_application_error(-20000, '僱員號不能重複');
WHEN e_integrity THEN
raise_application_error(-20001, '部門不存在');
END add_employee;
4.建立過程:帶有OUT引數
create or replaceprocedure qry_employee
(eno number,name outvarchar2,salary out number)
is
begin
selectename,sal into name,salary from emp where empno=eno;
exception
whenno_date_found then
raise_application_error(-20000,'該僱員不存在');
end;
當在應用程式中呼叫該過程時,必須要定義變數接受輸出引數的資料
sql>var name varchar2(10)
var salary number
exec qry_employee(7788,:name,:salary)
print name salary
5.建立過程:帶有INOUT引數(輸入輸出引數)
create or replaceprocedure compute
(num1 in outnumber,num2 in out number)
is
v1number;
v2number;
begin
v1:num1/num2;
v2:mod(num1,num2);
num1:=v1;
num2:=v2;
end;
sql>var n1 number
var n2 number
exec :n1:=100
exec :n2:=30
exec ecmpute(:n1,:n2)
print n1 n2
6.為引數傳遞變數和資料
位置傳遞,名稱傳遞,組合傳遞三種
1.位置傳遞:在呼叫子程式時按照引數定義的順序為引數指定相應的變數或數值
exec add_dept(40,'sales','new york');
exec add_dept(10);
2.名稱傳遞:在呼叫子程式時指定引數名,並使用關聯符號=>為其提供相應的數值或變數
execadd_dept(dname=>'sales',dno=>50);
exec add_dept(dno=>30);
3.組合傳遞:同時使用位置傳遞和名稱傳遞
exec add_dept(50,loc=>'new york');
execadd_dept(60,dname=>'sales',loc=>'newyork');
7.檢視過程原始碼
oracle會將過程名,原始碼以及其執行程式碼存放到資料字典中.執行時直接按照其執行程式碼執行
可查詢資料字典(user_source)
select textfrom user_source where name='add_dept';
刪除過程
dropprocedure add_dept;
函式
用於返回特定函式
語法:create [orreplace] function function_name
(argument1 [mode1] datatype1,
argument2 [mode2] datatype2,
.....)
returndatatype --函式頭部必須要帶有RETURN子句,至少要包含一條RETURN語句
is|as pl/sql block;
1.建立函式:不帶任何引數
create or replacefunction get_user
return varchar2
is
v_uservarchar2(100);
begin
selectusername into v_user from user_users;
returnv_user;
end;
2.使用變數接受函式返回值
sql>var v1 varchar2(100)
exec :v1:=get_user
print v1
在SQL語句中直接呼叫函式
selectget_user from d l;
使用DBMS_OUTPUT呼叫函式
setserveroutput on
execdbms_output.put_line('當前資料庫使用者:'||ger_user)
3.建立函式:帶有IN引數
create orreplace function get_sal(name in varchar2)
returnnumber
as
v_sal emp.sal%type;
begin
select sal into v_sal from emp where upper(ename)=upper(name);
return v_sal;
exception
when no_data_found then
raise_application_error(-20000,'該僱員不存在');
end;
4.建立函式:帶有out引數
create or replacefunction get_info(name varchar2,title out varchar2)
return varchar2
as
deptnamedept.dname%type;
begin
selecta.job,b.dname into title,deptname from emp a,dept b anda.deptno=b.deptno
andupper(a.ename)=upper(name);
returndeptname
exception
whenno_data_found then
raise_application_error(-20000,'該僱員不存在');
end;
sql>var job varchar2(20)
var dname varchar2(20)
exec :dname:=get_info('scott',:job)
print danme job
5.建立函式:帶有INOUT引數
create or replacefunction result(num1 number,num2 in out number)
return number
as
v_resultnumber(6);
v_remaindernumber;
begin
v_result:=num1/num2;
v_remainder:=mod(num1,num2);
num2:=v_remainder;
returnv_result;
exception
whenzero_divide then
raise_application_error(-20000,'不能除0');
end;
sql>var result1 number
var result2 number
exec :result2:=30
exec :result1:=result(100,:result2)
print result result2
6.函式呼叫限制
SQL語句中只能呼叫儲存函式(伺服器端),而不能呼叫客戶端的函式
SQL只能呼叫帶有輸入引數,不能帶有輸出,輸入輸出函式
SQL不能使用PL/SQL的特有資料型別(boolean,table,record等)
SQL語句中呼叫的函式不能包含INSERT,UPDATE和DELETE語句
7.檢視函式原始碼
oracle會將函式名及其原始碼資訊存放到資料字典中user_source
set pagesize 40
select text fromuser_source where name='result';
8.刪除函式
drop functionresult;
管理子程式
1.列出當前使用者的子程式
資料字典檢視USER_OBJECTS用於顯示當前使用者所包含的所有物件.(表,檢視,索引,過程,函式,包)
sql>col object_name format a20
select object_name,created,status from user_objects whereobject_type in ('procedure','function')
2.列出子程式原始碼
select text fromuser_source where name='raise_salsry';
3.列出子程式編譯錯誤
使用SHOWERRORS命令確定錯誤原因和位置
show errorsprocedure raise_salary
使用資料字典檢視USER_ERRORS確定錯誤原因和位置
col text formata50
selectline||'/'||position as "line/col",text error from user_errors wherename='raise_salary';
4.列出物件依賴關係
使用資料字典檢視USER_DEPENDENCIES確定直接依賴關係
select name,typefrom user_dependencies where referenced_name='emp';
使用工具檢視DEPTREE和IDEPTREE確定直接依賴和間接依賴關係
先執行SQL指令碼UTLDTREE.SQL來建立這兩個檢視和過程DEPTREE_FILL,然後呼叫DEPTREE_FILL填充這兩個檢視
sql>@%oracle_home%\rdbms\admin\utldtree
exec deptree_fill('TABLE','scott','emp')
執行後會將直接或間接依賴於SCOTT.EMP表的所有物件填充到檢視DEPTREE和IDEPTREE中.
select nested_level,name,type from deptree;
select * from ideptree
5.重新編譯子程式
當修改了被引用物件的結構時,就會將相關依賴物件轉變為無效(INVALID)狀態。
alter table emp addremark varchar2(10);
selectobject_name,object_type from user_objects wherestatus='invalid';
為了避免子程式的執行錯誤,應該重新編譯這些儲存物件
alter procedureadd_employee compile;
alter view dept10compile;
alter functionget_info compile;
開發包
包用於邏輯組合相關的PL/SQL型別,項和子程式,由包規範和包體組成
1.建立包規範:包規範是包與應用程式之間的介面,用於定義包的公用元件,包括常量,變數,遊標,過程,函式等
create [or replace]package package_name
is|as
p lic type and item declarations
s program specificationsend package_name;
create or replacepackage emp_package is
g_deptnonumber(3):=30;
procedureadd_employee(eno number,name varchar2,salary number,dno numberdefault g_deptno);
procedurefire_employee(eno number);
functionget_sal(eno number) return number;
end emp_package;
2.建立包體:用於實現包規範所定義的過程和函式
create [or replace]package body package_name
is|as
private type and item declarations
s program bodies
endpackage_name;
create or repalce package body emp_package is
functionvalidate_deptno(v_deptno number)
return boolean
is
v_temp int;
begin
select 1 into v_temp from dept where deptno=v_deptno;
return tr;
exception
when no_date_found then
return false;
end;
procedure add_employee(eno number,name varchar2,salary number,dnonumber default g_deptno)
is
begin
if validate_deptno(dno) then
insert into emp(empno,ename,sal,deptno)vals(eno,name,salsry,dno);
else
raise_application_error(-20010,'不存在該部門');
end if;
exception
when dup_val_on_index then
raise_application_error(-20012,'該僱員已存在');
end;
procedure fire_employee(eno number) is
begin
delete from emp where empno=eno;
if sql%notfound then
raise_application_error(-20012,'該僱員不存在');
end if;
end;
functionget_sal(eno number) return number
is
v_sal emp.sal%type;
begin
select sal into v_sal from emp where empno=eno;
return v_sal;
exception
whenno_data_found then
raise_application_error(-20012,'該僱員不存在');
end;
end emp_package;
3.呼叫包元件
3.1在同一個包內呼叫包元件
create or replacepackage body emp_package is
procedure add_employee(eno number,name va har2,salary number,dnonumber default g_deptno)
is
begin
ifvalidate_deptno(dno) then
insert into emp(empno,ename,sal,deptno)vals(eno,name,salary,dno);
else
raise_application_error(-20010,'該部門不存在')
end if;
exception
when dup_val_on_index then
raise_application_error(-20011,'該僱員已存在')
end;
.........
3.2呼叫包公用變數
execemp_package.g_deptno:=20
3.3呼叫包公用過程
execemp_package.add_employee(1111,'mary',2000)
3.4呼叫包公用函式
var salarynumber
exec:salary:=emp_package.get_sal(7788)
print salary
3.5以其他使用者身份呼叫包公用元件
connsystem/manager
execscott.emp_package.add_employee(1115,'scott',1200)
execscott.emp_package.fire_employee(1115)
3.6呼叫遠端資料庫包的公用元件
execemp_package.add_employee@orasrv(1116,'scott',1200)
4.檢視原始碼:存放在資料字典USER_SCOURCE中
select text fromuser_source where name='emp-package' and type='package';
5.刪除包
drop packageemp_package;
6.使用包過載
過載(overload)是指多個具有相同名稱的子程式
1.建立包規範
同名的過程和函式必須具有不同的輸入引數,同名函式返回值的資料型別必須完全相同
create or replacepackage overload is
functionget_sal(eno number) return number;
functionget_sal(name varchar2) return number;
procedurefile_employee(eno number);
procedurefile_employee(name varchar2);
end;
2.建立包體
必須要給不同的過載過程和過載函式提供不同的實現程式碼
create or replacepackage body overload is
function get_sal(eno number) return number
is
v_sal emp.sal%type;
begin
select sal into v_sal from emp where empno=eno;
return v_sal;
exception
when no_data_found then
raise_application_error(-20020,'該僱員不存在');
end;
function get_sal(name varchar2) return number
is
v_sal emp.sal%type;
begin
select sal into v_sal from emp where upper(ename)=upper(name);
return v_sal;
exception
when no_data_found then
raise_application_error(-20020,'該僱員不存在');
end;
procedure fire_employee(eno number) is
begin
delete from emp where empno=no;
if sql%notfound then
raise_application_error(-20020,'該僱員不存在');
end if;
end;
procedurefire_employee(name varchar2) is
begin
delete from emp where upper(ename)=upper(name);
if sql%notfound then
raise_application_error(-20020,'該僱員不存在');
end if;
end;
end;
3.呼叫過載過程和過載函式
var sal1 number
var sal2 number
exec:sal1:=overload.get_sal('scott')
exec:sal2:=overload.get_sal(7685)
execoverload.fire_employee(7369)
execoverload.fire_employee('scott')
7.使用包構造過程
類似於高階語言中的建構函式和構造方法
1.建立包規範
包的構造過程用於初始化包的全域性變數.
create or replacepackage emp_package is
minsalnumber(6,2);
maxsalnumber(6,2);
procedureadd_employee(eno number,name varchar2,salary number,dnonumber);
procedureupd_sal(eno number,salary number);
procedureupd_sal(name varchar2,salary number);
end;
2.建立包體
包的構造過程沒有任何名稱,它是實現了包的其他過程後,以BEGIN開始,END結束的部分
create or replacepackage body emp_package is
procedureadd_employee(eno number,name varchar2,salary number,dno number)
is
begin
if salarybetween minsal and maxsal then
insert into emp (empno,ename,sal,deptno)vals(eno,name,salary,dno);
else
raise_application_error(-20001,'工資不在範圍內');
end if;
exception
when dup_val_on_index then
raise_application_error(-20002,'該僱員已經存在');
end;
procedureupd_sal(eno number,salary number) is
begin
if salary between minsal and maxsal then
update emp set sal=salary where empno =eno;
if sql%notfound then
raise_application_error(-20003,'不存在僱員號');
end if;
else
raise_application_errpr(-20001,'工資不在範圍內');
end if;
end;
procedure upd_sal(name varchar2,salary number) is
begin
if salary between minsal and maxsal then
update emp set sal=salary where upper(ename)=upper(name);
if sql%notfound then
raise_application_error(-20004,'不存在該僱員名');
end if;
else
raise_application_error(-20001,'工資不在範圍內');
end if;
end;
begin
selectmi(sal),max(sal) into minsal,maxsal from emp ;
end;
呼叫包公用元件:構造過程只調用一次
execemp_package.add_employee(1111,'mary',3000,20)
execemp_package.upd_sal('mary',2000)
8.使用純度級別
在SQL中引用包的公用函式,該公用函式不能包含DML語句(insert,update,delete),也不能讀寫遠端包的變數
為了對包的公用函式加以限制,在定義包規範時,可以使用純度級別(purity level)限制公用函式
語法:pragmarestrict_references (function_name,wnds[,wnps][,rnds][,rnps]);
wnds:用於限制函式不能修改資料庫資料(禁止DML)
wnps:用於限制函式不能修改包變數(不能給包變數賦值)
rnds:用於限制函式不能讀取資料庫資料(禁止SELECT操作)
rnps:用於限制函式不能讀取包變數(不能將包變數賦值給其他變數)
1.建立包規範
create or replacepackage purity is
minsalnumber(6,2);
maxsalnumber(6,2);
functionmax_sal return number;
functionmin_sal return number;
pragmarestrict_references(max_sal,wnps);--不能修改
pragmarestrict_references(min_sal,wnps);
end;
2.建立包體
create or replacepackage body purity is
function max_sal return number
is
begin
return maxsal;
end;
functionmin_sal return number
is
begin
return minsal;
end;
begin
select min(sal),max(sal) into minsal,maxsal from emp;
end;
3.呼叫包的公用函式
var minsal number
var maxsal number
exec :minsal:=purity.minsal()
exec :maxsal:=purity.maxsal()
print minsal maxsal
編輯播報
DECLARE
salary emp.sal%TYPE := 0;
mgr_num emp.mgr%TYPE;
last_name emp.ename%TYPE;
starting_empno emp.empno%TYPE := 7499;
BEGIN
SELECT mgr INTO mgr_num FROM emp
WHERE empno = starting_empno;
WHILE salary <= 2500 LOOP
SELECT sal,mgr,ename INTO salary,mgr_num,last_name
FROM emp WHERE empno = mgr_num;
END LOOP;
INSERT INTO temp VALUES (NULL,salary,last_name);
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO temp VALUES (NULL,NULL,'Not found');
COMMIT;
END;
/*Please View The Example Code Reference*/
[3]