How to create id with AUTO_INCREMENT on Oracle?
似乎在Oracle中没有AUTO_INCREMENT的概念,直到包括版本11g。
如何在Oracle 11g中创建一个行为类似自动增量的列?
从Oracle 11g开始,Oracle中没有"auto_increment"或"identity"列。但是,您可以使用序列和触发器轻松地对其进行建模:
表定义:
1 2 3 4 5 6 7 8 | CREATE TABLE departments ( ID NUMBER(10) NOT NULL, DESCRIPTION VARCHAR2(50) NOT NULL); ALTER TABLE departments ADD ( CONSTRAINT dept_pk PRIMARY KEY (ID)); CREATE SEQUENCE dept_seq START WITH 1; |
触发定义:
1 2 3 4 5 6 7 8 9 10 | CREATE OR REPLACE TRIGGER dept_bir BEFORE INSERT ON departments FOR EACH ROW BEGIN SELECT dept_seq.NEXTVAL INTO :NEW.id FROM dual; END; / |
更新:
现在,Oracle 12c上提供了
1 2 3 4 | CREATE TABLE t1 ( c1 NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY, c2 VARCHAR2(10) ); |
或指定起始值和增量值,同时防止任何插入标识列(
1 2 3 4 | CREATE TABLE t1 ( c1 NUMBER GENERATED ALWAYS AS IDENTITY(START WITH 1 INCREMENT BY 1), c2 VARCHAR2(10) ); |
或者,Oracle 12还允许使用序列作为默认值:
1 2 3 4 5 6 7 8 | CREATE SEQUENCE dept_seq START WITH 1; CREATE TABLE departments ( ID NUMBER(10) DEFAULT dept_seq.nextval NOT NULL, DESCRIPTION VARCHAR2(50) NOT NULL); ALTER TABLE departments ADD ( CONSTRAINT dept_pk PRIMARY KEY (ID)); |
如果要创建递增数字键,则需要创建序列。
1 2 3 4 | CREATE SEQUENCE name_of_sequence START WITH 1 INCREMENT BY 1 CACHE 100; |
然后,您可以在
1 2 | INSERT INTO name_of_table( primary_key_column, <<other columns>> ) VALUES( name_of_sequence.nextval, <<other values>> ); |
或者,您可以定义一个触发器,使用序列自动填充主键值
1 2 3 4 5 6 7 8 | CREATE OR REPLACE TRIGGER trigger_name BEFORE INSERT ON TABLE_NAME FOR EACH ROW BEGIN SELECT name_of_sequence.nextval INTO :NEW.primary_key_column FROM dual; END; |
如果您使用的是Oracle 11.1或更高版本,则可以稍微简化触发器
1 2 3 4 5 6 | CREATE OR REPLACE TRIGGER trigger_name BEFORE INSERT ON TABLE_NAME FOR EACH ROW BEGIN :NEW.primary_key_column := name_of_sequence.nextval; END; |
如果你真的想使用
1 2 3 4 | CREATE TABLE TABLE_NAME ( primary_key_column raw(16) DEFAULT sys_guid() PRIMARY KEY, <<other columns>> ) |
在Oracle 12c以后你可以做类似的事情,
1 2 3 4 5 6 | CREATE TABLE MAPS ( MAP_ID INTEGER GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1) NOT NULL, MAP_NAME VARCHAR(24) NOT NULL, UNIQUE (MAP_ID, MAP_NAME) ); |
在Oracle(Pre 12c)中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | -- create table CREATE TABLE MAPS ( MAP_ID INTEGER NOT NULL , MAP_NAME VARCHAR(24) NOT NULL, UNIQUE (MAP_ID, MAP_NAME) ); -- create sequence CREATE SEQUENCE MAPS_SEQ; -- create tigger using the sequence CREATE OR REPLACE TRIGGER MAPS_TRG BEFORE INSERT ON MAPS FOR EACH ROW WHEN (NEW.MAP_ID IS NULL) BEGIN SELECT MAPS_SEQ.NEXTVAL INTO :NEW.MAP_ID FROM dual; END; / |
这有三种口味:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | -- numerical identity, e.g. 1,2,3... CREATE TABLE FOO ( x NUMBER PRIMARY KEY ); CREATE SEQUENCE FOO_seq; CREATE OR REPLACE TRIGGER FOO_trg BEFORE INSERT ON FOO FOR each ROW BEGIN SELECT FOO_seq.nextval INTO :NEW.x FROM dual; END; / -- GUID identity, e.g. 7CFF0C304187716EE040488AA1F9749A -- use the commented out lines if you prefer RAW over VARCHAR2. CREATE TABLE FOO ( x VARCHAR(32) PRIMARY KEY -- string version -- x raw(32) primary key -- raw version ); CREATE OR REPLACE TRIGGER FOO_trg BEFORE INSERT ON FOO FOR each ROW BEGIN SELECT CAST(sys_guid() AS varchar2(32)) INTO :NEW.x FROM dual; -- string version -- select sys_guid() into :new.x from dual; -- raw version END; / |
更新:
Oracle 12c引入了这两种不依赖于触发器的变体:
1 2 | CREATE TABLE mytable(id NUMBER DEFAULT mysequence.nextval); CREATE TABLE mytable(id NUMBER generated AS IDENTITY); |
第一个使用传统方式的序列;第二个在内部管理价值。
Oracle Database 12c引入了Identity,一个自动增量(系统生成的)列。
在以前的数据库版本中(直到11g),您通常通过创建序列和触发器来实现Identity。
从12c开始,您可以创建自己的表并定义必须作为标识生成的列。
以下文章介绍了如何使用它:
标识列 - Oracle Database 12c中的新条目
假设您的意思是像SQL Server标识列一样的列?
在Oracle中,您使用SEQUENCE来实现相同的功能。我会看看我是否能找到一个好的链接并在此发布。
更新:看起来你自己找到了它。无论如何这是链接:
http://www.techonthenet.com/oracle/sequences.php
当您想要任何人都可以轻松阅读/记忆/理解的序列号时,可以使用
1 2 3 | CREATE TABLE <table_name> (emp_id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY, name VARCHAR2(30)); |
现在,您的
您可以通过忽略emp_id列来在表中插入值。
1 | INSERT INTO <table_name> (name) VALUES ('name value'); |
因此,它会为您的
从Oracle 12c开始,可以通过以下两种方式之一支持Identity列:
序列+表 - 在此解决方案中,您仍然可以像往常一样创建序列,然后使用以下DDL:
CREATE TABLE MyTable
(ID号码默认MyTable_Seq.NEXTVAL,
...)
仅表 - 在此解决方案中,未明确指定序列。您将使用以下DDL:
CREATE TABLE MyTable(ID IDBER生成为身份,......)
如果您使用第一种方式,它向后兼容现有的做事方式。第二个是更直接的,并且与其他RDMS系统更加一致。
它被称为
1 2 3 4 5 | CREATE TABLE identity_test_tab ( id NUMBER GENERATED ALWAYS AS IDENTITY, description VARCHAR2 (30) ); |
插入
1 | INSERT INTO identity_test_tab (description) VALUES ('Just DESCRIPTION'); |
1 row created.
你不能像下面这样插入
1 | INSERT INTO identity_test_tab (id, description) VALUES (NULL, 'ID=NULL and DESCRIPTION'); |
ERROR at line 1: ORA-32795: cannot insert into a generated always
identity column
1 | INSERT INTO identity_test_tab (id, description) VALUES (999, 'ID=999 and DESCRIPTION'); |
ERROR at line 1: ORA-32795: cannot insert into a generated always
identity column
有用的链接
这是完整的解决方案w.r.t异常/错误处理自动增量,这个解决方案是向后兼容的,将适用于11g&amp; 12c,特别是如果应用程序正在生产中。
请将"TABLE_NAME"替换为相应的表名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | --checking if table already exisits BEGIN EXECUTE IMMEDIATE 'DROP TABLE TABLE_NAME'; EXCEPTION WHEN OTHERS THEN NULL; END; / --creating table CREATE TABLE TABLE_NAME ( ID NUMBER(10) PRIMARY KEY NOT NULL, . . . ); --checking if sequence already exists BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE TABLE_NAME_SEQ'; EXCEPTION WHEN OTHERS THEN NULL; END; --creating sequence / CREATE SEQUENCE TABLE_NAME_SEQ START WITH 1 INCREMENT BY 1 MINVALUE 1 NOMAXVALUE NOCYCLE CACHE 2; --granting rights as per required user group / GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE_NAME TO USER_GROUP; -- creating trigger / CREATE OR REPLACE TRIGGER TABLE_NAME_TS BEFORE INSERT OR UPDATE ON TABLE_NAME FOR EACH ROW BEGIN -- auto increment column SELECT TABLE_NAME_SEQ.NextVal INTO :NEW.ID FROM dual; -- You can also put some other required default data as per need of your columns, for example SELECT SYS_CONTEXT('USERENV', 'SESSIONID') INTO :NEW.SessionID FROM dual; SELECT SYS_CONTEXT('USERENV','SERVER_HOST') INTO :NEW.HostName FROM dual; SELECT SYS_CONTEXT('USERENV','OS_USER') INTO :NEW.LoginID FROM dual; . . . END; / |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | FUNCTION UNIQUE2( seq IN NUMBER ) RETURN VARCHAR2 AS i NUMBER := seq; s VARCHAR2(9); r NUMBER(2,0); BEGIN WHILE i > 0 LOOP r := MOD( i, 36 ); i := ( i - r ) / 36; IF ( r < 10 ) THEN s := TO_CHAR(r) || s; ELSE s := CHR( 55 + r ) || s; END IF; END LOOP; RETURN 'ID'||LPAD( s, 14, '0' ); END; |
这就是我在现有表和列(命名id)上执行此操作的方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | UPDATE TABLE SET id=ROWNUM; DECLARE maxval NUMBER; BEGIN SELECT MAX(id) INTO maxval FROM TABLE; EXECUTE IMMEDIATE 'DROP SEQUENCE table_seq'; EXECUTE IMMEDIATE 'CREATE SEQUENCE table_seq START WITH '|| TO_CHAR(TO_NUMBER(maxval)+1) ||' INCREMENT BY 1 NOMAXVALUE'; END; CREATE TRIGGER table_trigger BEFORE INSERT ON TABLE FOR EACH ROW BEGIN :NEW.id := table_seq.NEXTVAL; END; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | FUNCTION GETUNIQUEID_2 RETURN VARCHAR2 AS v_curr_id NUMBER; v_inc NUMBER; v_next_val NUMBER; pragma autonomous_transaction; BEGIN CREATE SEQUENCE sequnce START WITH YYMMDD0000000001 INCREMENT BY 1 NOCACHE SELECT SEQUENCE.nextval INTO v_curr_id FROM dual; IF(substr(v_curr_id,0,6)= to_char(sysdate,'yymmdd')) THEN v_next_val := to_number(to_char(SYSDATE+1, 'yymmdd') || '0000000000'); v_inc := v_next_val - v_curr_id; EXECUTE immediate ' alter sequence sequence increment by ' || v_inc ; SELECT SEQUENCE.nextval INTO v_curr_id FROM dual; EXECUTE immediate ' alter sequence sequence increment by 1'; ELSE dbms_output.put_line('exception : file not found'); END IF; RETURN 'ID'||v_curr_id; END; |
1 2 3 4 5 6 | CREATE TRIGGER t1_trigger BEFORE INSERT ON AUDITLOGS FOR each ROW BEGIN SELECT t1_seq.nextval INTO :NEW.id FROM dual; END; |
只需要用表名更改表名(AUDITLOGS),用new.column_name更改new.id
oracle在12c中有序列和标识列
http://www.oracle-base.com/articles/12c/identity-columns-in-oracle-12cr1.php#identity-columns
我发现了这个,但不确定rdb 7是什么
http://www.oracle.com/technetwork/products/rdb/0307-identity-columns-128126.pdf
也许只是尝试这个简单的脚本:
http://www.hlavaj.sk/ai.php
结果是:
1 2 3 4 5 6 7 8 | CREATE SEQUENCE TABLE_PK_SEQ; CREATE OR REPLACE TRIGGER TR_SEQ_TABLE BEFORE INSERT ON TABLE FOR EACH ROW BEGIN SELECT TABLE_PK_SEQ.NEXTVAL INTO :NEW.PK FROM dual; END; |