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

Oracle PL/SQL 入門實戰:從建表、資料初始化、複合查詢更新到觸發器審計與套件測試

     編輯:關於SqlServer

案例需求

  • 兩張表:`emp` (員工)、`dept` (部門)。
  • 建表、各寫入 5 筆測試資料。
  • 「技術部」員工薪水漲 20%。
  • 建立薪水變動審計日誌。
  • 建立測試套件。

1. 建表


CREATE TABLE emp (
    emp_id     NUMBER(5) PRIMARY KEY,
    emp_name   VARCHAR2(20),
    emp_salary NUMBER(4)
);

CREATE TABLE dept (
    dept_id   NUMBER(3) PRIMARY KEY,
    dept_name VARCHAR2(20),
    emp_id    NUMBER(5) REFERENCES emp(emp_id)
);

2. 資料初始化:參數化預存程序


CREATE OR REPLACE PROCEDURE ins_emp (
    p_id NUMBER, p_name VARCHAR2, p_sal NUMBER
) AS BEGIN
    INSERT INTO emp VALUES (p_id, p_name, p_sal);
END;
/

CREATE OR REPLACE PROCEDURE ins_dept (
    p_did NUMBER, p_dname VARCHAR2, p_eid NUMBER
) AS BEGIN
    INSERT INTO dept VALUES (p_did, p_dname, p_eid);
END;
/

BEGIN
    ins_emp(10000, '張三', 4000);
    ins_emp(10001, '李四', 2300);
    ins_emp(10002, '王五', 3500);
    ins_emp(10003, '趙六', 3500);
    ins_emp(10004, '錢七', 3500);

    ins_dept(111, '技術部', 10000);
    ins_dept(111, '技術部', 10001);
    ins_dept(111, '技術部', 10002);
    ins_dept(112, '業務部', 10003);
    ins_dept(113, '人資部', 10004);
END;
/

3. 複合查詢更新:指定部門加薪


CREATE OR REPLACE PROCEDURE raise_salary_by_dept (p_dept_name VARCHAR2) AS
BEGIN
    UPDATE emp
    SET emp_salary = emp_salary * 1.2
    WHERE emp_id IN (
        SELECT e.emp_id
        FROM emp e JOIN dept d ON e.emp_id = d.emp_id
        WHERE d.dept_name = p_dept_name
    );
END;
/

EXEC raise_salary_by_dept('技術部');

4. 觸發器:薪水變動審計日誌


CREATE TABLE salary_audit (
    audit_id    NUMBER GENERATED ALWAYS AS IDENTITY,
    emp_id      NUMBER(5),
    old_salary  NUMBER(4),
    new_salary  NUMBER(4),
    change_date DATE DEFAULT SYSDATE,
    changed_by  VARCHAR2(30) DEFAULT USER
);

CREATE OR REPLACE TRIGGER trg_emp_salary_audit
BEFORE UPDATE OF emp_salary ON emp
FOR EACH ROW
BEGIN
    IF :OLD.emp_salary != :NEW.emp_salary THEN
        INSERT INTO salary_audit (emp_id, old_salary, new_salary)
        VALUES (:OLD.emp_id, :OLD.emp_salary, :NEW.emp_salary);
    END IF;
END;
/

5. 測試套件


CREATE OR REPLACE PACKAGE pkg_emp_test AS
    PROCEDURE test_raise_salary;
    PROCEDURE test_audit_log;
END;
/

CREATE OR REPLACE PACKAGE BODY pkg_emp_test AS
    PROCEDURE test_raise_salary IS
        v_sal_before NUMBER;
        v_sal_after  NUMBER;
    BEGIN
        SELECT emp_salary INTO v_sal_before FROM emp WHERE emp_id = 10000;
        raise_salary_by_dept('技術部');
        SELECT emp_salary INTO v_sal_after FROM emp WHERE emp_id = 10000;
        ASSERT(v_sal_after = v_sal_before * 1.2, '薪水應漲 20%');
    END;

    PROCEDURE test_audit_log IS
        v_cnt NUMBER;
    BEGIN
        SELECT COUNT(*) INTO v_cnt FROM salary_audit WHERE emp_id = 10000;
        ASSERT(v_cnt = 1, '應產生一筆審計記錄');
    END;
END;
/

關鍵知識點總結

  • %TYPE / %ROWTYPE:錨定資料型別,結構變更自動適應。
  • 隱性游標屬性:`SQL%ROWCOUNT`、`SQL%FOUND`、`SQL%NOTFOUND` 判斷 DML 影響。
  • 觸發器時機:`BEFORE` 適合驗證/審計,`AFTER` 適合後續動作(如發送通知)。
  • 套件:規格與主體分離、封裝相關程序/函數/游標/型別、支援多載、狀態保持(Session 級)。
  • 單元測試:`utPLSQL` / `Oracle SQL Developer Unit Testing` 可自動化。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved