oracle 遊標,函式 function , 儲存過程 PROCEDURE , 觸發器 Trigger
function uf_execute_sql(as_where varchar2, as_sql varchar2) return varchar2 is
v_ret varchar2(30);
begin
execute immediate as_sql
into v_ret
using as_where; //using 後的引數為as_sql中的引數,若有多個依次新增,用逗號分割
return v_ret;
end;
2、 建立包
建立Oracle包是我們在使用Oracle資料庫時最常見的操作之一,下面就為您介紹建立Oracle包規範的語法,希望對您能有所幫助。
包是一種將過程、函式和資料結構捆綁在一起的容器;包由兩個部分組成:外部可視包規範,包括函式頭,過程頭,和外部可視資料結構;另一部分是包主體(package body),包主體包含了所有被捆綁的過程和函式的宣告、執行、異常處理部分。
打包的PL/SQL程式和沒有打包的有很大的差異,包資料在使用者的整個會話期間都一直存在,當用戶獲得包的執行授權時,就等於獲得包規範中的所有程式和資料結構的許可權。但不能只對包中的某一個函式或過程進行授權。包可以過載過程和函式,在包內可以用同一個名字宣告多個程式,在執行時根據引數的數目和資料型別呼叫正確的程式。
建立Oracle包必須首先建立包規範,建立Oracle包規範的語法如下:
1. CREATE [OR REPLACE] PACKAGE package_name
2. {AS|IS}
3. public_variable_declarations |
4. public_type_declarations |
5. public_exception_declarations |
6. public_cursor_declarations |
7. function_declarations |
8. procedure_specifications
9. END [package_name]
建立包主體使用CREATE PACKAGE BODY語句:
1. CREATE [OR REPLACE] PACKAGE BODY package_name
2. {AS|IS}
3. private_variable_declarations |
4. private_type_declarations |
5. private_exception_declarations |
6. private_cursor_declarations |
7. function_declarations |
8. procedure_specifications
9. END [package_name]
私有資料結構是那些在包主體內部,對被呼叫程式而言是不可見的。
********************儲存過程************************************
子程式 是已經命名的PLSQL塊,他們儲存在資料庫中,可以為他們指定引數,可以在客戶端和
應用程式中呼叫它們。
子程式包括 儲存過程 和 函式,程式包 是儲存過程和 函式的集合。
儲存過程--語法:
CREATE [OR REPLACE] PROCEDURE procedure_name
[(parameter_list)]
{IS|AS}
[local_declarations]
BEGIN
executable_statements
[EXCEPTION
exception_handlers]
END [procedure_name];
語法說明:
procedure_name 是過程名字
parameter_list 是引數列表
local_declarations 是區域性宣告
executable_statements 是可執行語句,
execption_handlers是 異常處理程式
-------
create or replace procedure wyd_print(times number)
is
i number :=0;
begin
loop
i :=i+1;
DBMS_OUTPUT.PUT_LINE('第'||i||'次 迴圈!!');
exit when i>= times;
end loop;
end;
/
直接呼叫儲存過程:
exec wyd_print(20)
execute wyd_print(30);
過程引數模式
呼叫程式是通過引數向被呼叫的過程傳遞值的。
引數傳遞的模式有3種:IN ,OUT ,IN OUT 。也就是輸入,輸出,輸入 輸出
定義過程引數的語法:
parameter_name [IN |OUT |IN OUT] datatype [{:=| DEFAULT} expression]
引數IN模式 是預設模式
如果要指定OUT | IN OUT 模式引數 要 明確指定
---------
例項:
CREATE OR REPLACE PROCEDURE mypar(a IN number,b OUT number,c IN OUT number)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('a -->'||a);
DBMS_OUTPUT.PUT_LINE('b -->'||b);
DBMS_OUTPUT.PUT_LINE('c -->'||c);
--a:=111;
b:=222;
c:=333;
DBMS_OUTPUT.PUT_LINE('a -->'||a);
DBMS_OUTPUT.PUT_LINE('b -->'||b);
DBMS_OUTPUT.PUT_LINE('c -->'||c);
END mypar;
/
-----
declare
aa number:=11;
bb number:=22;
cc number:=33;
begin
DBMS_OUTPUT.PUT_LINE('before aa -->'||aa);
DBMS_OUTPUT.PUT_LINE('before bb -->'||bb);
DBMS_OUTPUT.PUT_LINE('before cc -->'||cc);
mypar(aa,88,cc);
DBMS_OUTPUT.PUT_LINE('after aa -->'||aa);
DBMS_OUTPUT.PUT_LINE('after bb -->'||bb);
DBMS_OUTPUT.PUT_LINE('after cc -->'||cc);
end;
/
注意幾點:
(1)IN型別引數 在 過程中不能 再給賦值
(2)OUT INOUT 型別 可以進入後賦值。
(3)OUT 型別引數在呼叫過程傳入引數時無效,
(4)OUT ,IN OUT 型別引數 在呼叫過程時傳入的必須是變數
---------
一個過程建立了,將執行許可權授予其他使用者
語法:
GRANT EXECUTE ON procedure_name TO USER_Name; //授權給特定使用者執行過程的許可權
GRANT EXECUTE ON procedure_name TO public ; //授權給所有資料庫使用者執行過程的許可權
檢視資料庫裡面的儲存過程:
select object_name from user_objects where object_type='PROCEDURE';
select substr(object_name,1,20) object_name,object_type from user_objects where object_type='PROCEDURE';
select substr(object_name,1,10) object_name,object_type from user_objects;
刪除一個過程:
DROP procedure procedure_name;
____________________________________________________________________
_______________ 函式的 定義 和 使用 ____________________
____________________________________________________________________
函式與過程相似,也是資料庫中儲存的已經命名的PL/SQL塊。
函式的主要特性:
(1)必須有一個返回值
(2)函式不能單獨執行,只能通過SQL語句 或者PL/SQL程式塊來呼叫。
函式定義 -- 語法:
CREATE [OR REPLACE] FUNCTION function_name
[(parameter1,parameter2...)]
RETURN datatype
{IS|AS}
[local_declarations]
BEGIN
Exexutable_Statements;
[EXCEPTION
Exception_handlers;]
END;
/
注意:
(1)函式只能帶有 IN 引數,而不能帶有 IN OUT 或 OUT 引數。
(2)形式引數必須只能使用資料庫型別,不能使用PL/SQL型別。
(3)函式返回型別也必須是資料庫型別。
--------------
建立一個函式:
create or replace function fun_sum(a number,b number)
return number
IS
BEGIN
return a+b;
END;
--------------
通過SQL來執行函式:
SELECT function_name[(parameter1,parameter2...)] FROM DUAL;
select fun_sum(5,6) from dual;
--------------
檢視資料庫裡面的使用者建立的函式:
select object_name from user_objects where object_type='FUNCTION';
select substr(object_name,1,20) object_name,object_type from user_objects where object_type='FUNCTION';
--------------
函式的授權:
GRANT EXECUTE ON function_name TO USER_Name; //函式的使用權授予特定的使用者
GRANT EXECUTE ON function_name TO public; //函式的使用權授予資料庫中所有使用者
example:
GRANT EXECUTE ON fun_sum to public;
--------------
*** 自主事務處理
自主事務處理 是有另一個事務處理(主事務處理) 啟動的獨立事務處理。
舉例:
//P1就是 自主事務處理
CREATE OR REPLACE PROCEDURE p1
AS
PRAGMA AUTONOMOUS_TRANSACTION; --就這句話,讓事務處理獨立開來了
BEGIN
END p1;
/
CREATE OR REPLACE PROCEDURE p2
AS
BEGIN
...
p1;
...
END p2;
/
p2 過程 呼叫 了P1 過程,但是 p1過程聲明瞭事務獨立,
使得p1的執行對p2沒有直接影響。
刪除一個函式:
語法:
DROP FUNCTION Function_name;
Example:
drop FUNCTION fun_sum;
****************** 包 的建立 和使用 ****************
----------------------------------------------------------------
程式包是一種資料庫物件,它是對相關PL/SQL型別,子程式,遊標,異常,變數
和常量的封裝。
建立一個程式包 有兩個步驟:
(1) 建立 程式包規範。(也可以說成是 ‘宣告程式包’)
基本語法:
CREATE [OR PEPLACE] PACKAGE package_name
IS|AS
[public type and item declarations]
[subprogram specifications]
END [package_name];
/
------------
(2) 建立 程式包主體。(也可以說成是‘實現程式包’)
基本語法:
CREATE [OR REPLACE] PACKAGE BODY package_name
IS|AS
[Public type and item declarations]
[Subprogram bodies]
[BEGIN
Initialization_statements]
END [package_name];
package_name
Public type and item declarations 宣告變數,常量,遊標,異常 或者 型別。
Subprogram bodies 定義公共和私有PL/SQL子程式
------------------
實際例子:
(1)建立程式包規範:
CREATE OR REPLACE PACKAGE wyd_package
IS
PROCEDURE wyd_print(name varchar2);
FUNCTION wyd_sum(a number,b number) return number;
END wyd_package;
(2)建立程式包主體:
CREATE OR REPLACE PACKAGE BODY wyd_package
AS
--實現wyd_print 儲存過程
PROCEDURE wyd_print(name varchar2) IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Hello,'||name);
END wyd_print;
--實現wyd_sum 函式
FUNCTION wyd_sum(a number,b number) RETURN NUMBER
IS
BEGIN
return a+b;
END wyd_sum;
END wyd_package;
-----------
呼叫建立的包中的儲存過程 和 函式
set serveroutput on
exec wyd_package.wyd_print('WangYuDong');
select wyd_package.wyd_sum(12,55) from dual;
-----------
檢視資料庫裡面的使用者建立的程式包:
select object_name from user_objects where object_type='PACKAGE';
select substr(object_name,1,20) object_name,object_type from user_objects;
select substr(object_name,1,20) object_name,object_type from user_objects where object_type='PACKAGE';
刪除一個程式包:
語法:
DROP PACKAGE PACKAGE_name;
Example:
drop package wyd_package;
********************** 觸發器 *****************************
觸發器 是當特定事件出現時自動執行的程式碼塊。
觸發器與過程的區別在於:
過程 是由使用者 或 程式 顯式呼叫的,
而觸發器是不能被直接呼叫的。Oracle會在事件請求觸發器時,執行適當的觸發器。
觸發器 可以用加強Oracle的 預設功能,提供高度可定製的資料庫。觸發器能夠執行
的功能有:
》自動生成資料
》強制複雜的完整性約束
》自定義複雜的安全許可權
》提供審計和日誌記錄
》啟用複雜的業務邏輯
觸發器的一般語法:
CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE|AFTER|INSTEAD OF}
{INSERT|DELETE|UPDATE[OF column[,column]...]}
[OR {INSERT|DELETE|UPDATE [OF column[,column]...]}]
ON [schema.]table_or_view_name
[REFERENCING [NEW AS new_row_name] [OLD AS old_row_name]]
[FOR EACH ROW]
[WHERE(condition)]
[DECLARE
variable_declation]
BEGIN
statements;
[EXCEPTION
exception_handlers]
END [trigger_name];
----------------
select to_char(sysdate,'yyyy-mm-dd hh12:mi:ss') from dual;
----------------
例項01:
CREATE OR REPLACE TRIGGER s_emp_trigger
BEFORE
INSERT OR DELETE OR UPDATE OF salary,name,id on s_emp
FOR EACH ROW
DECLARE
e_outtime EXCEPTION;
time_now varchar2(2);
time_upper varchar2(2) :='08';
time_lower varchar2(2) :='19';
BEGIN
time_now :=to_char(sysdate,'hh24');
IF time_now <time_upper or time_now>time_lower THEN
RAISE e_outtime;
ELSE DBMS_OUTPUT.PUT_LINE('修改資料庫成功!!');
END IF;
EXCEPTION
WHEN e_outtime THEN
RAISE_APPLICATION_ERROR(-2222,'資料庫在工作時間以外不允許修改!!');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('出現未知異常!!');
END;
/
上面的觸發器 是 限制 在 一天中8 點到19點 以外的時間修改表 s_emp;
----------------
測試 觸發器
insert into S_EMP(ID,NAME,SALARY)
VALUES('5','yangguo','5000');
----------------
例項02:
CREATE OR REPLACE TRIGGER student_trigger
BEFORE
INSERT OR UPDATE OF name on student
FOR EACH ROW
BEGIN
:new.name:='wangyudong';
END;
/
----
上面的觸發器是把要插入的值進行了更換,使得原先插入的name的value被修改為'wangyudong'
insert into student(id,name,class)
values('2','zhang','class2');
/
______________________________
觸發器的組成部分:
1,觸發器語句
觸發器語句是那些可以導致觸發器的事件,
既在表或者檢視上執行的INSERT,DELETE和UPDATE之類的
DML(Data manipulation language 資料庫操縱語言)語言,
在模式物件上執行的DDL(Data definition language
資料庫定義語句)語句或資料庫事件。
[insert|delete|update] of [column,[column..]]on [tableName |viewName]
or
[insert|delete|update] of [column,[column..]]on [tableName |viewName]
[FOR EACH ROW]//寫的話是行級 ,不寫就是語句級別
2,觸發器限制
觸發器限制條件包含一個boolean表示式,該值必須為真才能啟用觸發器。
如果該值為假或未知,將不會觸發。
[WHEN(condition)]
3,觸發器操作
觸發器操作是觸發器的主體,包含一些SQL語句和程式碼,這些程式碼在執行觸發器語句
且觸發器限制條件的值為真時執行。
行級觸發器允許觸發操作中的語句訪問行的列值。
[DECLARE
variable_declation]
BEGIN
statements;
[EXCEPTION
exception_handlers]
END [trigger_name];
----------------------------------------------------------------
觸發器型別:
1,行級別觸發器
行級別觸發器對DML語句影響的每個行執行一次。如果是UPDATE語句,可能影響
多行,也就多次執行觸發器。
可以在CREATE TRIGGER命令中指定FOR EACH ROW子句建立行級別觸發器
new.column 表示要插入更新的列的新值
old.column 表示要插入更新的列的舊值
:new.column := new_value 表示給新的列值變數賦值
用到new.column and old.column 一般在 行級別觸發器的 BEFORE 觸發器裡面使用
2,語句級別觸發器
語句級別觸發器對每一個DML語句執行一次。如果一個INSERT語句在表中插入200行,那麼
在表上的INSERT語句級別觸發器只執行一次。
語句級別的觸發器以便不用於處理於資料相關的操作,通常用於強制實施在表上的安全
措施。語句級別觸發器是CREAT TRIGGER命令建立的觸發器的預設型別。
3,INSTEAD OF 觸發器
INSTEAD OF 觸發器是在檢視上而不是在表上定義的觸發器,它是用來替換所有使用實際語句
的觸發器。這樣的觸發器可以用於克服Oracle在任何檢視上設定的限制,允許擁護修改不能直接
修改的檢視。
舉例:
SET SERVEROUTPUT ON
CREATE OR REPLACE TRIGGER student_trigger
INSTEAD OF
INSERT OR UPDATE OF name on student_view
FOR EACH ROW
BEGIN
DBMS_OUTPUT.PUT_LINE('這檢視是不允許被操作的!!');
END;
/
4,模式觸發器
相當於是帳戶級別觸發器
在Oracle資料庫中有多個帳戶。
可以在模式級別的操作上建立觸發器,如 CREATE,ALTER,DROP,GRANT,
REVOKE和 TRUNCATE 等DDL語句。
使用者可以建立觸發器類防止刪除自己建立的表。
模式觸發器提供的主要功能是阻止DDL操作以及在發生DDL操作的時候提供
額外的安全監控。
語法:
______________________________________
CREATE OR REPLACE TRIGGER trigger_name
{BEFORE|AFTER}trigger_event
ON [schema.]SCHEMA
WHEN(trigger.condition)
trigger_body;
_______________________________________
例項:
(1)我們來建立一個表來存放刪除表的資訊:
create table dropped_object(
obj_name varchar2(30),
obj_type varchar2(30),
drop_date DATE
);
(2)我們來建立一個模式級別的觸發器。用來記錄被刪除的物件
CREATE OR REPLACE TRIGGER log_drop_obj
AFTER DROP ON SCHEMA
BEGIN
INSERT INTO dropped_object(obj_name,obj_type,drop_date)
values(ORA_DICT_OBJ_NAME,ORA_DICT_OBJ_TYPE,SYSDATE);
END;
5,資料庫級別觸發器
可以建立在資料庫事件上的觸發器,包括啟動,關閉,伺服器錯誤,登陸和登出等。
這些都是例項範圍的,不與特定的表或檢視關聯。可以使用這種型別的觸發器自動進行
資料庫的維護和審計活動。
語法-例子:
CREATE OR REPLACE TRIGGER system_startup
AFTER STARTUP ON DATABASE
BEGIN
--Do something
END;
/
_______________________________________________________________
_______________________________________________________________
啟用和禁用觸發器
觸發器一旦建立,預設就立即生效。我們也可以手動將觸發器停止或者啟動。
起用或者禁用已知道的觸發器
語法:
ALTER TRIGGER trigger_name {ENABLE|DISABLE};
起用或者禁用在特定表上建立的所有觸發器
語法:
ALTER TABLE table_name {ENABLE|DISABLE} ALL TRIGGERS;
檢視有關觸發器的資訊
DESC USER_TRIGGERS;
SELECT TRIGGER_NAME FROM USER_TRIGGERS;
刪除觸發器
語法:
DROP TRIGGER <trigger_name>;
_____________________________________________________________________________________________________________________
*************************************** 遊標管理********************************************************************
遊標是構建在PL/SQL中,用來查詢資料,獲得記錄集合的指標。他可以讓開發者一次訪問結果集中一行。
遊標的分類:
遊標分為:
靜態遊標
|
----隱式遊標
|
----顯式遊標 (特殊的有循環遊標)
REF遊標(引用遊標)
//**********************************
隱式遊標
所有的SQL資料操縱語句 (QML)都有隱式宣告遊標,稱為隱式遊標。
隱式遊標是使用者不能直接命名和控制的遊標。
隱式遊標的四個屬性:
%FOUND
只有用在DML語句影響一行的多行的時候,%FOUND屬性返回TRUE,否則返回FALSE
%NOTFOUND
與%FOUND屬性的作用相反,如果DML沒有影響任何行,返回TRUE,否則返回FALSE
%ROWCOUNT
返回DML影響資料庫表的行數,值是 0 到 多
%ISOPEN
返回遊標是否被開啟的訊息。在執行SQL語句之後,Oracle自動關閉SQL遊標,所以
隱式遊標的%ISOPEN屬性始終是關閉的。
SQL%FOUND
SQL%NOTFOUND
SQL%ROWCOUNT
SQL%ISOPEN
----------------
操作
set serveroutput on
begin
insert into s_emp(id,name,salary) values('1','tom','4000');
--要執行的sql語句
IF sql%found THEN
DBMS_OUTPUT.PUT_LINE('用sql%found得知表更新了!');
ELSE
DBMS_OUTPUT.PUT_LINE('用sql%found得知表沒更新!');
END IF;
--用sql%found來判斷是否更新資料庫了
IF sql%notfound THEN
DBMS_OUTPUT.PUT_LINE('用sql%notfound 得知表沒有更新!!');
ELSE
DBMS_OUTPUT.PUT_LINE('用sql%notfound 得知表更新了!!');
END IF;
DBMS_OUTPUT.PUT_LINE('表更新了---->'||sql%rowcount||'行');
--用sql%rowcount來檢視更新了多少行
if sql%isopen then
dbms_output.put_line('cursor is open');
else
dbms_output.put_line('cursor is close');
end if;
--用sql%isopen來檢視遊標是否關閉了
DBMS_OUTPUT.PUT_LINE('end!!');
end;
/
----------------
----------------------------------------------------------------------------------------------
顯式遊標:
顯式遊標是使用者宣告的遊標,查詢返回的行集合可以包含 0行到多行。
顯式遊標的標準操作過程:
(1)宣告遊標。
(2)開啟遊標。
(3)從遊標中獲取記錄。
(4)關閉遊標。
------------------------
(1)宣告遊標:
CURSOR cursor_name [(parameter[,parameter]....)]
[RETURN return_type]
is select_statement;
cursor_name : 遊標名稱
parameter : 遊標指定輸入引數
return_type : 定義遊標提取的行的型別
select_statement : 指遊標定義的查詢語句
(2)
OPEN cursor_name [(parameters)];
(3)
FETCH cursor_name INTO variables;
cursor_name : 指遊標的名字
variables : 變數名
(4)
// 在處理完遊標中的所有行之後,必須關閉遊標,以釋放分配給遊標中的所有資源。
CLOSE cursor_name;
-----------
%FOUND
如果執行最後一條FETCH語句成功提取行,返回TRUE,否則返回FALSE
%NOTFOUND
如果執行最後一條FETCH語句成功提取行,返回FALSE,否則返回TRUE
%ISOPEN
如果遊標關閉,返回FALSE,遊標開啟,返回TRUE
%ROWCOUNT
返回到目前位置遊標提取的行數。當成功FETCH一行後,數量+1;
-------
例項:
set serveroutput on
declare
emp_id s_emp.id%type;
emp_name s_emp.name%type;
emp_salary s_emp.salary%type;
cursor emp_cur is
select id,name,salary from s_emp;
begin
open emp_cur;
loop
fetch emp_cur into emp_id,emp_name,emp_salary;
exit when emp_cur%notfound;
dbms_output.put_line('emp id -->'||emp_id||',emp name-->'||emp_name||',emp salary-->'||emp_salary);
end loop;
close emp_cur;
end;
/
-------
顯式遊標的特殊情況:循環遊標
可以使用循環遊標簡化顯式遊標的處理程式碼。 循環遊標隱式開啟遊標,自動從活動集獲取行,然後在處理完所有行時關閉遊標。
循環遊標自動建立%ROWTYPE型別的變數並且將此變數用作記錄索引。
語法:
FOR record_index IN cursor_name
LOOP
executable_statements;
END LOOP;
-----------
具體例項:
SET SERVEROUTPUT ON
DECLARE
CURSOR emp_cur is
select id,name,salary from s_emp;
BEGIN
--其中emp_rec 是一個存放一行的變數。我們在使用前不需要先宣告。直接用
for emp_rec in emp_cur
LOOP
DBMS_OUTPUT.PUT_LINE('EMP ID-->'||emp_rec.id||' EMP NAME-->'||emp_rec.name||' EMP SALARY-->'||emp_rec.salary);
END LOOP;
END;
------------
REF 遊標 (引用遊標)
REF遊標 可以在執行的時候決定執行何種查詢。
使用過程:
1,建立遊標
TYPE ref_cursor_name IS REF CURSOR [RETURN record_type];
註釋:return 語句是可選擇子句,用於指定遊標提取結果集的返回型別。
如果沒有return那麼遊標型別是一個弱型別。
2,在PLSQL的執行部分開啟遊標變數。用於開啟REF遊標的語法:
OPEN cursor_name FOR select_statement;
or OPEN cursor_name FOR dynamic_select_string [USING bing_argument_list];
----------
例項01
DECLARE
sqls VARCHAR2(200);
p_salary number:=8500;
id number;
name varchar2(50);
salary number;
TYPE cursor_salary IS REF CURSOR;
ref_cursor cursor_salary;
BEGIN
sqls :='select id from s_emp where salary>:1 ';
open ref_cursor FOR sqls USING p_salary;
DBMS_OUTPUT.PUT_LINE('薪水大於8500的人的ID有:');
LOOP
fetch ref_cursor into id;
EXIT WHEN ref_cursor%notfound;
DBMS_OUTPUT.PUT_LINE('ID='||id);
END LOOP;
--close ref_cursor;
END;
/
例項02
DECLARE
type emp is record(
id s_emp.id%type,
name s_emp.name%type,
salary s_emp.salary%type
);
p_salary number:=8500;
id number;
name varchar2(50);
salary number;
TYPE cursor_salary IS REF CURSOR RETURN emp;
ref_cursor cursor_salary;
BEGIN
open ref_cursor FOR select id,name,salary from s_emp where salary>8500;
DBMS_OUTPUT.PUT_LINE('薪水大於8500的人的ID有:');
LOOP
fetch ref_cursor into id,name,salary;
EXIT WHEN ref_cursor%notfound;
DBMS_OUTPUT.PUT_LINE('ID='||id||',name='||name||',salary='||salary);
END LOOP;
close ref_cursor;
END;
/
得出幾點:
(1)在宣告ref遊標 的時候要用記錄型別來宣告 return
(2)遊標查詢結果<select 得出的結果>一定要和 宣告的記錄型別對應。
(3)不要忘了關閉遊標變數