存儲過程(Stored Procedure)是 Oracle 數據庫中一組預編譯的 PL/SQL 語句集合,存儲在數據庫中并可通過名稱調用執行。它們是企業級數據庫應用開發的核心組件。
目錄
一、存儲過程基礎
1. 存儲過程特點
2. 創建基本語法
3. 存儲過程優點
4. 簡單示例
二、沒有參數的存儲過程
1. 簡單示例
三、有參數的存儲過程
1. 參數模式
2. 有輸入值 IN
3. 有輸出值 OUT
4. 有輸入輸出值IN OUT
(1)編譯:
(2)調用?編輯
(3)宏&輸入名稱?編輯
(4)查看輸出結果
四、存儲過程的調用總結
五、存儲過程中的DML操作
1. 基本DML示例
2. 使用RETURNING子句
六、異常處理
1. 預定義異常
2. 自定義異常
七、游標處理
1. 顯式游標
2. REF游標(動態游標)
八、高級特性
1. 自治事務
2. 批量處理(FORALL)
3. 條件編譯
九、存儲過程管理
1. 查看存儲過程
右鍵查看
2. 重新編譯
右鍵重新編譯
右鍵編輯--執行
3. 權限控制
4. 刪除存儲過程
十、最佳實踐
十一、存儲過程和函數的區別
一、存儲過程基礎
1. 存儲過程特點
-
預編譯執行:提高性能,減少解析開銷
-
模塊化設計:促進代碼重用和維護
-
增強安全性:通過權限控制保護數據
-
減少網絡流量:客戶端只需調用過程名而非發送多句SQL
-
事務控制:可在過程中管理完整事務
2. 創建基本語法
CREATE [OR REPLACE] PROCEDURE procedure_name[(parameter1 [IN|OUT|IN OUT] datatype [DEFAULT|:= value],parameter2 [IN|OUT|IN OUT] datatype [DEFAULT|:= value],...)]
[IS|AS][declaration_section]
BEGINexecutable_section
[EXCEPTIONexception_section]
END [procedure_name];
/create {or replace} procedure pro_name(v1 in/out/in out 類型)
as/is
{聲明變量}
begin
要執行的語句;
end;
/(1)創建 creat or replace procedure
(2)聲明變量
(3)開始 begin
(4)DML操作
(5)異常處理 exception
(6)結束 end
3. 存儲過程優點
(1)存儲過程只在創建時進行編譯,以后每次執行都不需要重新編譯,而一般的SQL語句每執行一次就編譯一次,所以使用存儲過程可以提高數據庫的執行速度。
(2)當對數據庫進行復雜操作時(比如對多個表進行查詢、修改操作),可以將此復雜的事務處理結合一起使用這些操作。如果用SQL需要多次連接數據庫,如果用存儲過程,只需要連接一次數據庫。
(3)存儲過程可以重復使用,可以減少數據庫開發人員的工作量。
4. 簡單示例
CREATE OR REPLACE PROCEDURE update_employee_salary( --創建--存過主題結構
---------------------------------------------------------------------------------p_emp_id IN employees.employee_id%TYPE,p_percent IN NUMBER DEFAULT 10
) ASv_old_salary employees.salary%TYPE; --聲明變量--存過主題結構
---------------------------------------------------------------------------------
BEGIN --開始--存過主題結構
----------------------------------------------------------------------------------- 獲取當前薪資SELECT salary INTO v_old_salaryFROM employeesWHERE employee_id = p_emp_id;-- 更新薪資UPDATE employeesSET salary = salary * (1 + p_percent/100)WHERE employee_id = p_emp_id;-- 輸出結果DBMS_OUTPUT.PUT_LINE('員工ID ' || p_emp_id || ' 薪資從 ' || v_old_salary || ' 調整為 ' || (v_old_salary * (1 + p_percent/100)));COMMIT; --DML操作--存過主題結構
---------------------------------------------------------------------------------
EXCEPTIONWHEN NO_DATA_FOUND THENDBMS_OUTPUT.PUT_LINE('錯誤: 未找到員工ID ' || p_emp_id);ROLLBACK;WHEN OTHERS THENDBMS_OUTPUT.PUT_LINE('錯誤: ' || SQLERRM);ROLLBACK; --異常處理--存過主題結構
---------------------------------------------------------------------------------
END update_employee_salary; --結束--存過主題結構
---------------------------------------------------------------------------------
/
二、沒有參數的存儲過程
1. 簡單示例
--編寫一個存儲過程,將emp表中和編號7788相同部門的員工信息插入到
--emp3中,將工作為CLERK的工資加300后插入到emp4中。
-- 創建
create or replace procedure pro2 as --創建--存過主題結構
begin --開始--存過主題結構
--------------------------------------------------------------------DML操作insert into emp3select *from empwhere deptno = (select deptno from emp where empno = 7788);--DML操作insert into emp4select e.empno,e.ename,e.job,e.mgr,e.hiredate,e.sal + 300,e.comm,e.deptnofrom emp ewhere job = 'CLERK';
------------------------------------------------------------------
end; --結束--存過主題結構
/
-- 調用:
call pro2();
-- 查詢、驗證
select * from emp3;
select * from emp4;
三、有參數的存儲過程
1. 參數模式
模式 | 描述 | 示例 |
IN | 只讀參數(默認) | p_id IN NUMBER |
OUT | 只寫參數,返回給調用者 | p_result OUT VARCHAR2 |
IN OUT | 可讀寫參數 | p_counter IN OUT NUMBER |
2. 有輸入值 IN
--輸入員工編號,輸出姓名和薪資。
-- 創建
create or replace procedure pro1(v_empno number) asv_name varchar2(20);v_sal emp.sal%type;
beginselect ename, sal into v_name, v_sal from emp where empno = v_empno;dbms_output.put_line(v_name || v_sal);
end;
-- 調用:
call pro1(7788);【調用方法】
在sql窗口 call pro_name(參數); --sql窗口括號不能省
在命令窗口 exec pro_name(參數);/*===============================================================================*/
【練習1】
--創建一張emp3數據同emp
--更改emp3的sal列的長度為number(20,2)
--編寫一個存儲過程
--輸入一個數字和一個部門編號
--要求數字是0-9的整數(如果不是,拋出異常,并打印'請輸入0-9的整數')
--當部門人數小于該數字,將該部門的員工信息插入到emp1--顯示插入了多少行
--當部門人數大于該數字,將該部門的員工姓名,編號刪除--并顯示刪除了多少人
--當部門人數等于該數字,不該部門的全部員工工資變成原工資的二次方--并顯示增加了多少人的工資
-- 準備:
CREAT TABLE EMP3 AS SELECT * FORM EMP;
ALTER TABLE EMP3 MODIFY SAL NUMBER(20,2);
-- 創建:
CREATE OR REPLACE PROCEDURE PRO_3(V1 NUMBER,V_DEPTNO NUMBER) AS
ERR EXCEPTION;
V3 NUMBER;
BEGINIF v1 NOT IN (0,1,2,3,4,5,6,7,8,9)THENRAISE ERR;END IF;