表 `USERINFO` 需要 `ID` 欄位自動遞增,Oracle 11g/12c 前無原生 Identity,需組合 **Sequence (序列) + Before Insert Trigger (觸發器)** 實現。
CREATE TABLE userinfo (
id NUMBER NOT NULL, -- 自增主鍵
name VARCHAR2(40)
);
CREATE SEQUENCE seq_userinfo
MINVALUE 1
START WITH 1
INCREMENT BY 1
CACHE 20
NOORDER
NOCYCLE;
CREATE OR REPLACE TRIGGER trg_userinfo_pk
BEFORE INSERT ON userinfo
FOR EACH ROW
BEGIN
SELECT seq_userinfo.NEXTVAL INTO :NEW.id FROM dual;
END;
/
-- 測試
INSERT INTO userinfo (name) VALUES ('Alice');
INSERT INTO userinfo (name) VALUES ('Bob');
SELECT * FROM userinfo;
-- ID 自動生成 1, 2...
INSERT INTO userinfo (name) VALUES ('Charlie')
│
▼
┌─────────────────────────────┐
│ BEFORE INSERT TRIGGER │
│ trg_userinfo_pk │
│ 1. SELECT seq.NEXTVAL │
│ 2. :NEW.id := 值 │
└─────────────────────────────┘
│
▼
INSERT 實際寫入 (id=3, name='Charlie')
│
▼
COMMIT → Sequence 值持久化,下次 NEXTVAL=4
-- 12c+ 直接建表
CREATE TABLE userinfo_new (
id NUMBER GENERATED ALWAYS AS IDENTITY (START WITH 1 CACHE 20),
name VARCHAR2(40)
);
-- 遷移舊表 (12.2+)
ALTER TABLE userinfo MODIFY id GENERATED ALWAYS AS IDENTITY;
-- 並手工 DROP SEQUENCE seq_userinfo; DROP TRIGGER trg_userinfo_pk;
| 問題 | 原因 | 解決 |
|---|---|---|
| 主鍵重複 ORA-00001 | 手工 INSERT 指定 ID 與 Sequence 值衝突 | 應用層禁止指定 ID;或改用 `GENERATED BY DEFAULT ON NULL AS IDENTITY` (12c+) |
| Sequence 值跳躍 (非連續) | 緩存值未用完實例重啟/崩潰丟失 | 業務可接受非連續;極度要求連續需 `NOCACHE` (效能損) |
| RAC 環境 Sequence 爭用 | 多實例搶字典鎖獲取 NEXTVAL | 加大 `CACHE` (如 1000)、使用 `NOORDER` |
| Trigger 失效/編譯錯誤 | DDL 變更導致 Trigger INVALID | DDL 後檢查 `USER_TRIGGERS.STATUS`,需時 `ALTER TRIGGER ... COMPILE` |
Sequence + Trigger 是 Oracle 11g 及之前實現自增主鍵的 **標準模式**,穩定、可控、跨版本通用。12c+ 專案請直接使用 **Identity Column**,零維護、原生效能、DDL 簡潔。理解兩者內部機制,才能在遷移、排錯、效能調優中遊刃有餘。