如果你經(jīng)常使用 MySQL霜瘪,你肯定對 AUTO_INCREMENT 非常熟悉,因?yàn)榻?jīng)常要用到它惧磺。
一颖对、什么是自增列?
自增列是數(shù)據(jù)庫中值隨插入的每個(gè)行自動(dòng)增加的一列磨隘。它最常用于主鍵或 ID 字段缤底,這樣每次增加一行時(shí),不用指該字段的值番捂,它就會(huì)自動(dòng)增加个唧,而且是唯一的。
當(dāng)在 MySQL 中定義列時(shí)白嘁,我們可以指定一個(gè)名為 AUTO_INCREMENT 的參數(shù)坑鱼。然后膘流,每當(dāng)將新值插入此表中時(shí)絮缅,放入此列的值比最后一個(gè)值加 1。
但很不幸呼股,Oracle 沒有 AUTO_INCREMENT 功能耕魄。 那要如何在Oracle中做到這一點(diǎn)呢?
二彭谁、在 Oracle 11g 中設(shè)置自增字段
1. 創(chuàng)建表
首先創(chuàng)建一張用于測試的表:
CREATE TABLE "TEST" (
ID NUMBER(11) PRIMARY KEY,
NAME VARCHAR2(50BYTE) NOT NULL
);
2. 創(chuàng)建序列
然后創(chuàng)建一個(gè)名為 TEST_ID_SEQ 的序列(序列名稱自己隨意設(shè)定):
CREATE SEQUENCE TEST_ID_SEQ
INCREMENT BY 1
START WITH 100
MAXVALUE 999999999
NOCYCLE
NOCACHE;
如果要?jiǎng)h除序列吸奴,可以使用下面的 SQL 命令:
DROP SEQUENCE TEST_ID_SEQ;
對 SEQUENCE 的一些說明:
- INCREMENT BY 用于指定序列增量(默認(rèn)值:1),如果指定的是正整數(shù)缠局,則序列號(hào)自動(dòng)遞增则奥,如果指定的是負(fù)數(shù),則自動(dòng)遞減狭园。
- START WITH 用于指定序列生成器生成的第一個(gè)序列號(hào)读处,當(dāng)序列號(hào)順序遞增時(shí)默認(rèn)值為序列號(hào)的最小值,當(dāng)序列號(hào)順序遞減時(shí)默認(rèn)值為序列號(hào)的最大值唱矛。
- MAXVALUE 用于指定序列生成器可以生成的組大序列號(hào)(必須大于或等于 START WITH罚舱,并且必須大于 MINVALUE),默認(rèn)為 NOMAXVALUE绎谦。
- MINVALUE 用于指定序列生成器可以生成的最小序列號(hào)(必須小于或等于 START WITH管闷,并且必須小于 MAXVALUE),默認(rèn)值為 NOMINVALUE窃肠。
- CYCLE 用于指定在達(dá)到序列的最大值或最小值之后是否繼續(xù)生成序列號(hào)包个,默認(rèn)為 NOCYCLE。
- CACHE 用于指定在內(nèi)存中可以預(yù)分配的序列號(hào)個(gè)數(shù)(默認(rèn)值:20)冤留。
到這一步其實(shí)就已經(jīng)可以實(shí)現(xiàn)字段自增碧囊,只要插入的時(shí)候恃锉,將 ID 的值設(shè)置為序列的下一個(gè)值 TEST_ID_SEQ.NEXTVAL 就可以了:
SQL> INSERT INTO "TEST" ("ID", "NAME") VALUES (TEST_ID_SEQ.NEXTVAL, 'name1');
SQL> INSERT INTO "TEST" ("ID", "NAME") VALUES (TEST_ID_SEQ.NEXTVAL, 'name2');
SQL> INSERT INTO "TEST" ("ID", "NAME") VALUES (TEST_ID_SEQ.NEXTVAL, 'name3');
SQL> SELECT * FROM "TEST";
ID NAME
--- ------
100 name1
101 name2
102 name3
為了簡化插入操作,我們還可以創(chuàng)建一個(gè)觸發(fā)器呕臂,當(dāng)將數(shù)據(jù)插入到 "TEST" 表的時(shí)候破托,自動(dòng)將最新的 ID 插入進(jìn)去。
3. 創(chuàng)建觸發(fā)器
CREATE OR REPLACE TRIGGER TEST_ID_SEQ_TRG
BEFORE INSERT ON "TEST"
FOR EACH ROW
WHEN (NEW."ID" IS NULL)
BEGIN
SELECT TEST_ID_SEQ.NEXTVAL
INTO :NEW."ID"
FROM DUAL;
END;
這樣的話歧蒋,每次寫插入語句土砂,只需要將 ID 字段的值設(shè)置為 NULL 它就會(huì)自動(dòng)遞增了:
SQL> INSERT INTO "TEST" ("ID", "NAME") VALUES (NULL, 'name4');
SQL> INSERT INTO "TEST" ("ID", "NAME") VALUES (NULL, 'name5');
SQL> INSERT INTO "TEST" ("ID", "NAME") VALUES (NULL, 'name6');
SQL> SELECT * FROM "TEST";
ID NAME
--- ------
100 name1
101 name2
102 name3
103 name4
104 name5
105 name6
4. 一些值得注意的地方
4.1 插入指定 ID
如果某條插入語句指定了 ID 的值如:
SQL> INSERT INTO "TEST" ("ID", "NAME") VALUES (1000, 'name1001');
SQL> SELECT * FROM "TEST";
ID NAME
--- ------
100 name1
101 name2
102 name3
103 name4
104 name5
1000 name1001
那么下次 ID 還是會(huì)在原來的基礎(chǔ)上繼續(xù)增加:
SQL> INSERT INTO "TEST" ("ID", "NAME") VALUES (NULL, 'name1001');
SQL> SELECT * FROM "TEST";
ID NAME
--- ------
100 name1
101 name2
102 name3
103 name4
104 name5
1000 name1001
但當(dāng)序列的值到了 1000 的時(shí)候,如果 ID 允許重復(fù)谜洽,就會(huì)有兩行記錄 ID 都為 1000萝映。
但如果 ID 設(shè)置為了主鍵,如本文的例子 ID NUMBER(11) PRIMARY KEY阐虚,則插入就會(huì)報(bào)錯(cuò):
Error : ORA-00001: unique constraint (SOFTWARE.SYS_C0014995) violated
4.2 字段加引號(hào)
在 SQL 語句中序臂,字段最好都加上引號(hào),不然可能會(huì)報(bào)錯(cuò):
Error : ORA-00900: invalid SQL statement
或:
ORA-24344: Success with Compilation Error
4.3 SQUENCE
- 第一次 NEXTVAL 返回的是初始值实束;隨后的 NEXTVAL 會(huì)自動(dòng)增加 INCREMENT BY 對應(yīng)的值奥秆,然后返回增加后的值。
- CURRVAL 總是返回當(dāng)前 SEQUENCE 的值咸灿,但是在第一次 NEXTVAL 初始化之后才能使用 CURRVAL 构订,否則會(huì)出錯(cuò)。
- 一次 NEXTVAL 會(huì)增加一次 SEQUENCE 的值避矢,所以如果在同一個(gè)語句里面使用多個(gè)NEXTVAL悼瘾,其值就是不一樣的。
- 如果指定 CACHE 值审胸,Oracle 就可以預(yù)先在內(nèi)存里面放置一些 SEQUENCE亥宿,這樣存取的快些。 CACHE 里面的取完后砂沛,Oracle 自動(dòng)再取一組到 CACHE烫扼。
- 但使用 CACHE 或許會(huì)跳號(hào),比如數(shù)據(jù)庫突然不正常關(guān)閉(shutdown abort)尺上, CACHE 中的 SEQUENCE 就會(huì)丟失材蛛。所以可以在 CREATE SEQUENCE 的時(shí)候用 NOCACHE 防止這種情況。
4.4 性能
在數(shù)據(jù)庫操作中怎抛,觸發(fā)器的使用耗費(fèi)系統(tǒng)資源相對較大卑吭。如果對于表容量相對較小的表格我們可以忽略觸發(fā)器帶來的性能影響。
考慮到大表操作的性能問題马绝,需要盡可能的減少觸發(fā)器的使用豆赏。對于以上操作,就可以拋棄觸發(fā)器的使用,直接手動(dòng)調(diào)用序列函數(shù)即可掷邦,但這樣可能在程序維護(hù)上稍微帶來一些不便白胀。
三、實(shí)現(xiàn)自增ID,實(shí)現(xiàn)步驟順序總結(jié)
- 創(chuàng)建ID為主鍵的表(PRIMARY KEY)
- 創(chuàng)建序列
- 創(chuàng)建觸發(fā)器
- 每個(gè)表都需要按順序123建一次抚岗,工程量浩大
四或杠、在 Oracle 12c 中設(shè)置自增字段
在 Oracle 12c 中設(shè)置自增字段就簡單多了,因?yàn)?ORacle 12c 提供了 IDENTITY 屬性:
CREATE TABLE "TEST" (
ID NUMBER(11) GENERATED BY DEFAULT ON NULL AS IDENTITY,
NAME VARCHAR2(50BYTE) NOT NULL
);
這樣就搞定了宣蔚!和 MySQL 一樣簡單向抢!??????
五、總結(jié)
所以如上所屬胚委,在 Oracle 中設(shè)置自增字段挟鸠,需要根據(jù)不同的版本使用不同的方法:
在 Oracle 11g 中,需要先創(chuàng)建序列(SQUENCE)再創(chuàng)建一個(gè)觸發(fā)器(TRIGGER)亩冬。
在 Oracle 12c 中艘希,只需要使用 IDENTITY 屬性就可以了。