Bagaimana cara membuat id dengan AUTO_INCREMENT di Oracle?

422

Tampaknya tidak ada konsep AUTO_INCREMENT di Oracle, hingga dan termasuk versi 11g.

Bagaimana saya bisa membuat kolom yang berperilaku seperti kenaikan otomatis di Oracle 11g?

Sushan Ghimire
sumber
3
Anda dapat membuat BEFORE INSERTpemicu di atas meja dan menarik nilai dari urutan untuk membuat kenaikan otomatis
Hunter McMillen
7
Kolom identitas sekarang tersedia di Oracle 12c docs.oracle.com/cd/E16655_01/gateways.121/e22508/…
David Aldridge
Apakah Anda menggunakan Oracle RAC? Menggunakan CACHED di akhir pernyataan dapat meningkatkan kinerja. Jika Anda melakukan banyak menyisipkan dalam waktu singkat (dan pemesanan tidak penting bagi Anda), pertimbangkan pemicu penyisipan urutan yang terhuyung-huyung untuk manfaat kinerja tambahan. Lihat: dba-oracle.com/t_rac_proper_afterence_usage.htm
Peeter Kokk

Jawaban:

596

Tidak ada yang namanya kolom "auto_increment" atau "identitas" di Oracle pada Oracle 11g . Namun, Anda dapat memodelkannya dengan mudah dengan urutan dan pemicu:

Definisi tabel:

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;

Definisi pemicu:

CREATE OR REPLACE TRIGGER dept_bir 
BEFORE INSERT ON departments 
FOR EACH ROW

BEGIN
  SELECT dept_seq.NEXTVAL
  INTO   :new.id
  FROM   dual;
END;
/

MEMPERBARUI:

IDENTITY kolom sekarang tersedia di Oracle 12c:

create table t1 (
    c1 NUMBER GENERATED by default on null as IDENTITY,
    c2 VARCHAR2(10)
    );

atau tentukan nilai awal dan kenaikan, juga mencegah penyisipan ke kolom identitas ( GENERATED ALWAYS) (sekali lagi, hanya Oracle 12c +)

create table t1 (
    c1 NUMBER GENERATED ALWAYS as IDENTITY(START with 1 INCREMENT by 1),
    c2 VARCHAR2(10)
    );

Atau, Oracle 12 juga memungkinkan untuk menggunakan urutan sebagai nilai default:

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));
Eugenio Cuevas
sumber
5
Saya seorang n00b, bisakah Anda memberi tahu saya dari mana dept_seqasalnya!
J86
3
CREATE SEQUENCE dept_seq; menciptakan dept_seq ... seperti tabel .. tetapi dalam kasus ini hanya angka yang dapat Anda tambahkan dengan dept_seq.NEXTVAL ... lihat pemicunya.
Benjamin Eckstein
Seperti yang disebutkan, kode asli akan gagal ketika menemukan garis dengan ID yang ditentukan. Tetapi bagaimana dengan kasus ini: Pemicu akan menetapkan id (secara otomatis) hanya jika tidak ada id yang ditentukan secara eksplisit di INSERT. Ini akan gagal, bukan? Dan apa cara yang tepat untuk melakukan ini?
FanaticD
10
Untuk pemula oracle seperti saya, bagian 'id' dari 'new.id' merujuk ke kolom 'id' pada tabel di atas. 'baru' adalah kata khusus yang merujuk pada baris baru yang dibuat
Hoppe
2
Anda tidak perlu menggunakan SELECT .. INTOpemicu yang bisa Anda lakukan :new.id := dept_seq.NEXTVAL;.
MT0
90

SYS_GUIDmengembalikan GUID - ID unik global. A SYS_GUIDadalah a RAW(16). Itu tidak menghasilkan nilai numerik yang bertambah.

Jika Anda ingin membuat kunci numerik yang bertambah, Anda ingin membuat urutan.

CREATE SEQUENCE name_of_sequence
  START WITH 1
  INCREMENT BY 1
  CACHE 100;

Anda kemudian akan menggunakan urutan itu dalam INSERTpernyataan Anda

INSERT INTO name_of_table( primary_key_column, <<other columns>> )
  VALUES( name_of_sequence.nextval, <<other values>> );

Atau Anda dapat menentukan pemicu yang secara otomatis mengisi nilai kunci utama menggunakan urutan

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;

Jika Anda menggunakan Oracle 11.1 atau lebih baru, Anda dapat menyederhanakan pelatuk sedikit

CREATE OR REPLACE TRIGGER trigger_name
  BEFORE INSERT ON table_name
  FOR EACH ROW
BEGIN
  :new.primary_key_column := name_of_sequence.nextval;
END;

Jika Anda benar-benar ingin menggunakannya SYS_GUID

CREATE TABLE table_name (
  primary_key_column raw(16) default sys_guid() primary key,
  <<other columns>>
)
Gua Justin
sumber
1
Apa yang CACHE 100; in CREATE SEQUENCE name_of_sequence START WITH 1 INCREMENT BY 1 CACHE 100;harus dilakukan
Angelina
3
CACHE 100: kata kunci mengambil 100 angka berikutnya ke memori. Biasanya SEQUENCE disimpan ke dalam basis data kapan pun nilainya berubah, jika Anda menyimpannya, itu akan disimpan dan diambil hanya jika yang di-cache habis. Memberi Anda keuntungan kinerja yang signifikan, tetapi jika database gagal, Anda kehilangan semua nilai cache yang bahkan tidak Anda gunakan.
Ramazan Polat
2
A SYS_GUID()adalah a RAW(16), bukan 32.
turbanoff
2
@turbanoff - Tangkapan bagus. Memperbarui jawaban saya. The SYS_GUIDdokumentasi menyatakan suatu raw(32)yang bingung.
Justin Cave
@JustinCave Saya telah menggunakan pendekatan Anda dalam membuat urutan dan pemicu. Bagaimana jika saya menghapus baris secara terprogram (java), apakah ID (kunci utama) akan disesuaikan juga?
kittu
52

Di Oracle 12c dan seterusnya Anda bisa melakukan sesuatu seperti,

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)
);

Dan di Oracle (Pre 12c).

-- 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;
/
Nisar
sumber
2
@JonHeller Saya pribadi mengatakan IDENTITYcontohnya jauh lebih jelas dalam jawaban ini.
EpicPandaForce
5
Tidak WHEN (new.MAP_ID IS NULL)ada dalam jawaban yang diterima. Terpilih.
dcsohl
1
@dcsohl, WHEN ( new.MAP_ID is null)bukan kode yang baik dalam kasus ini dan sudah dijelaskan di bagian komentar oleh @ABCade di bawah jawaban yang diterima .. sudah dibaca;)
ajmalmhd04
Ketika saya menjalankan ini dari CREATE OR REPLACE TRIGGERke END;, saya mendapatkan jendela "Enter Binds". Jika saya mengklik "Terapkan" dan tidak melakukan hal lain di jendela itu, dan kemudian menjalankan ALTER TRIGGERperintah, semuanya baik, tetapi berharap ada cara untuk secara terprogram menyingkirkan pop-up itu dan menjalankan semuanya bersama-sama. Jika Anda mencobanya secara bersamaan, Anda mendapatkan PLS-00103: Encountered the symbol 'ALTER'dan itu tidak suka EXECUTE IMMEDIATE, baik (kesalahan yang sama, hanya mengatakannya saja Encountered the symbol 'EXECUTE').
vapcguy
Saya dapatkan [42000][907] ORA-00907: missing right parenthesisketika menjalankan versi untuk Oracle 12c dan seterusnya. Ada ide ?
belgoros
32

Berikut ini tiga rasa:

  1. numerik . Peningkatan nilai numerik sederhana, misalnya 1,2,3, ....
  2. GUID . pengidentifikasi universal global, sebagai RAWtipe data.
  3. GUID (string) . Sama seperti di atas, tetapi sebagai string yang mungkin lebih mudah ditangani dalam beberapa bahasa.

xadalah kolom identitas. Ganti FOOdengan nama tabel Anda di masing-masing contoh.

-- 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;
/

memperbarui:

Oracle 12c memperkenalkan dua varian ini yang tidak bergantung pada pemicu:

create table mytable(id number default mysequence.nextval);
create table mytable(id number generated as identity);

Yang pertama menggunakan urutan dengan cara tradisional; yang kedua mengelola nilai secara internal.

Mark Harrison
sumber
7

Anggap Anda maksud kolom seperti kolom identitas SQL Server?

Di Oracle, Anda menggunakan SEQUENCE untuk mencapai fungsi yang sama. Saya akan melihat apakah saya dapat menemukan tautan yang bagus dan mempostingnya di sini.

Pembaruan: sepertinya Anda menemukannya sendiri. Inilah tautannya: http://www.techonthenet.com/oracle/ followingences.php

Phil Sandler
sumber
7

Oracle Database 12c memperkenalkan Identity, kolom auto-incremental (dihasilkan sistem). Dalam versi database sebelumnya (hingga 11g), Anda biasanya menerapkan Identitas dengan membuat Sequence dan Trigger. Dari 12c dan seterusnya, Anda dapat membuat Tabel Anda sendiri dan menentukan kolom yang harus dihasilkan sebagai Identitas.

Artikel berikut menjelaskan cara menggunakannya:

Kolom identitas - Entri baru dalam Oracle Database 12c

Corrado Piola
sumber
5
Meskipun tautan ini dapat menjawab pertanyaan, lebih baik untuk memasukkan bagian-bagian penting dari jawaban di sini dan memberikan tautan untuk referensi. Jawaban hanya tautan dapat menjadi tidak valid jika halaman tertaut berubah.
Jembatan
5

Triggerdan Sequencedapat digunakan ketika Anda menginginkan nomor seri agar siapa pun dapat dengan mudah membaca / mengingat / mengerti. Tetapi jika Anda tidak ingin mengelola Kolom ID (seperti emp_id) dengan cara ini, dan nilai kolom ini tidak terlalu besar, Anda bisa menggunakan SYS_GUID()Table Creation untuk mendapatkan Peningkatan Otomatis seperti ini.

CREATE TABLE <table_name> 
(emp_id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
name VARCHAR2(30));

Sekarang emp_idkolom Anda akan menerima "nilai pengidentifikasi unik global". Anda bisa memasukkan nilai dalam tabel dengan mengabaikan kolom emp_id seperti ini.

INSERT INTO <table_name> (name) VALUES ('name value');

Jadi, itu akan memasukkan nilai unik ke emp_idKolom Anda .

124
sumber
Apa yang terjadi ketika satu baris dihapus? Apakah SYS_GUID()id-nya juga bernilai?
kittu
5

Dimulai dengan Oracle 12c ada dukungan untuk kolom Identity dalam satu dari dua cara:

  1. Sequence + Table - Dalam solusi ini Anda masih membuat urutan seperti biasa, maka Anda menggunakan DDL berikut:

    BUAT Tabel MyTable (ID NUMBER DEFAULT MyTable_Seq.NEXTVAL , ...)

  2. Tabel Saja - Dalam solusi ini tidak ada urutan yang ditentukan secara eksplisit. Anda akan menggunakan DDL berikut:

    CREATE TABLE MyTable (ID NUMBER DIHASILKAN SEBAGAI IDENTITAS , ...)

Jika Anda menggunakan cara pertama itu kompatibel dengan cara yang ada dalam melakukan sesuatu. Yang kedua sedikit lebih mudah dan lebih sejalan dengan sisa sistem RDMS di luar sana.

Nate Zaugg
sumber
5

itu disebut Identity Columnsdan hanya tersedia dari Oracle oracle 12c

CREATE TABLE identity_test_tab
(
   id            NUMBER GENERATED ALWAYS AS IDENTITY,
   description   VARCHAR2 (30)
);

contoh masukkan ke dalam Identity Columnsseperti di bawah ini

INSERT INTO identity_test_tab (description) VALUES ('Just DESCRIPTION');

1 baris dibuat.

Anda TIDAK bisa memasukkan seperti di bawah ini

INSERT INTO identity_test_tab (id, description) VALUES (NULL, 'ID=NULL and DESCRIPTION');

GALAT di baris 1: ORA-32795: tidak bisa disisipkan ke kolom identitas selalu yang dihasilkan

INSERT INTO identity_test_tab (id, description) VALUES (999, 'ID=999 and DESCRIPTION');

GALAT di baris 1: ORA-32795: tidak bisa disisipkan ke kolom identitas selalu yang dihasilkan

tautan bermanfaat

sam
sumber
1

Inilah solusi lengkap penanganan pengecualian / kesalahan wrt untuk kenaikan otomatis, solusi ini kompatibel mundur dan akan bekerja pada 11g & 12c, khususnya jika aplikasi sedang dalam produksi.

Harap ganti 'TABLE_NAME' dengan nama tabel yang sesuai

--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;
/
emkays
sumber
0

Ini adalah bagaimana saya melakukan ini pada tabel dan kolom yang ada (bernama id):

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;
eter6
sumber
0
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;
kumar venkatesan
sumber
0
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;
kumar venkatesan
sumber
-1

oracle memiliki urutan dan kolom identitas dalam 12c

http://www.oracle-base.com/articles/12c/identity-columns-in-oracle-12cr1.php#identity-columns

Saya menemukan ini tetapi tidak yakin apa rdb 7 adalah http://www.oracle.com/technetwork/products/rdb/0307-identity-columns-128126.pdf

Kalpesh Soni
sumber
Informasi bermanfaat dan perbandingan kinerja yang menarik. Menggunakan kolom IDENTITAS lebih baik daripada menggunakan TRIGGER untuk SEQUENCE.
ygoe
-1
  create trigger t1_trigger
  before insert on AUDITLOGS
  for each row
   begin
     select t1_seq.nextval into :new.id from dual;
   end;

hanya saya harus mengubah nama tabel (AUDITLOGS) dengan nama tabel Anda dan new.id dengan new.column_name

abhishek ringsia
sumber
-2

Mungkin coba saja skrip sederhana ini:

http://www.hlavaj.sk/ai.php

Hasilnya adalah:

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;
Martin Hlavaj
sumber
3
Bagaimana ini berbeda dari jawaban eugnio? Plus: Anda tidak memerlukan selectversi Oracle modern. Anda cukup menggunakan:new.pk := TABLE_PK_SEQ.NEXTVAL
a_horse_with_no_name