首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

Oracle PL/SQL 存儲過程與函數完整開發指南:從基礎語法到進階參數應用

     編輯:關於SqlServer

核心概念區分

特性Procedure(存儲過程)Function(函數)
返回值無返回值(可透過 OUT/IN OUT 參數回傳)必須有 RETURN 值
調用方式獨立語句:EXEC proc_name(...); 或 CALL proc_name(...);嵌入 SQL 表達式:SELECT func_name(...) FROM dual;
事務控制可包含 COMMIT/ROLLBACK通常不建議包含 DML 提交
主要用途執行業務邏輯、批次作業、資料維護計算、轉換、查詢輔助、可用於 SQL 子句

PL/SQL 區塊結構

DECLARE
  -- 宣告區(選填):變數、游標、例外、型別定義
  v_sal NUMBER;
BEGIN
  -- 執行區(必填):業務邏輯、SQL 操作、流程控制
  SELECT sal INTO v_sal FROM emp WHERE empno = 7369;
  DBMS_OUTPUT.PUT_LINE('薪資: ' || v_sal);
EXCEPTION
  -- 例外處理區(選填):錯誤捕獲與處理
  WHEN NO_DATA_FOUND THEN
    DBMS_OUTPUT.PUT_LINE('查無此員工!');
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('系統錯誤: ' || SQLERRM);
END;
/

建立與管理存儲過程

最簡過程

CREATE OR REPLACE PROCEDURE myproc AS
BEGIN
  NULL; -- 空操作
END;
/

帶參數過程

CREATE OR REPLACE PROCEDURE get_emp_sal (p_empno IN NUMBER) AS
  v_sal NUMBER;
BEGIN
  SELECT sal INTO v_sal FROM emp WHERE empno = p_empno;
  DBMS_OUTPUT.PUT_LINE('員工 ' || p_empno || ' 薪資: ' || v_sal);
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    DBMS_OUTPUT.PUT_LINE('員工編號 ' || p_empno || ' 不存在');
END;
/

參數模式詳細解析

模式方向特性典型用途
IN呼叫端 → 過程預設、唯讀、可傳常數/變數/運算式輸入條件、查詢參數
OUT過程 → 呼叫端初始為 NULL、需指派值、僅能傳變數回傳計算結果、狀態碼
IN OUT雙向傳入初始值、可修改並回傳、按地址傳遞累計器、狀態物件、大物件操作

OUT/IN OUT 參數實戰範例

CREATE OR REPLACE PROCEDURE calc_bonus (
  p_base_sal   IN  NUMBER,
  p_bonus_rate IN  NUMBER,
  p_bonus_amt  OUT NUMBER,
  p_total_sal  IN OUT NUMBER
) AS
BEGIN
  p_bonus_amt := p_base_sal * p_bonus_rate;
  p_total_sal := p_total_sal + p_bonus_amt;
END;
/

-- 呼叫測試
DECLARE
  v_bonus  NUMBER;
  v_total  NUMBER := 50000; -- 原總薪資
BEGIN
  calc_bonus(50000, 0.15, v_bonus, v_total);
  DBMS_OUTPUT.PUT_LINE('獎金: ' || v_bonus || ', 新總薪: ' || v_total);
END;
/

函數開發範例

標量函數

CREATE OR REPLACE FUNCTION get_emp_name (p_empno IN NUMBER) RETURN VARCHAR2 AS
  v_ename VARCHAR2(50);
BEGIN
  SELECT ename INTO v_ename FROM emp WHERE empno = p_empno;
  RETURN v_ename;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    RETURN 'UNKNOWN';
END;
/

-- SQL 中調用
SELECT get_emp_name(7369) FROM dual;

表值函數

CREATE OR REPLACE TYPE emp_rec AS OBJECT (
  empno NUMBER, ename VARCHAR2(50), sal NUMBER
);
CREATE OR REPLACE TYPE emp_tab AS TABLE OF emp_rec;

CREATE OR REPLACE FUNCTION get_dept_emps (p_deptno IN NUMBER) RETURN emp_tab PIPELINED AS
BEGIN
  FOR r IN (SELECT empno, ename, sal FROM emp WHERE deptno = p_deptno) LOOP
    PIPE ROW (emp_rec(r.empno, r.ename, r.sal));
  END LOOP;
  RETURN;
END;
/

-- 當作資料表使用
SELECT * FROM TABLE(get_dept_emps(10));

實務應用:用戶驗證過程

CREATE TABLE app_users (
  user_id   NUMBER PRIMARY KEY,
  username  VARCHAR2(30) UNIQUE,
  password  VARCHAR2(100),
  role_id   NUMBER
);

CREATE OR REPLACE PROCEDURE check_login (
  p_username IN  VARCHAR2,
  p_password IN  VARCHAR2,
  p_result   OUT VARCHAR2,
  p_user_id  OUT NUMBER,
  p_role     OUT NUMBER
) AS
  v_cnt NUMBER;
BEGIN
  SELECT COUNT(*), user_id, role_id
  INTO v_cnt, p_user_id, p_role
  FROM app_users
  WHERE username = p_username AND password = p_password;

  IF v_cnt = 1 THEN
    p_result := 'SUCCESS';
  ELSE
    p_result := 'INVALID_CREDENTIALS';
    p_user_id := NULL;
    p_role := NULL;
  END IF;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    p_result := 'INVALID_CREDENTIALS';
  WHEN OTHERS THEN
    p_result := 'SYSTEM_ERROR: ' || SQLERRM;
END;
/

最佳實踐建議

  1. 命名規範:過程用動詞前綴(proc_, sp_),函數用名詞/動詞(fn_, get_, calc_)
  2. 參數預設值:CREATE PROCEDURE p(p_param IN NUMBER DEFAULT 0) ...
  3. 例外處理:盡量捕獲具體例外,避免只用 WHEN OTHERS 吞沒錯誤
  4. 效能優化:使用 BULK COLLECT、FORALL 處理大量資料;適當加入 PRAGMA AUTONOMOUS_TRANSACTION 處理日誌記錄
  5. 版本控管:所有 DDL 腳本納入 Git 管理,部署前進行 Code Review
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved