Làm cách nào để tạo id với AUTO_INCREMENT trên Oracle?


422

Dường như không có khái niệm về AUTO_INCREMENT trong Oracle, cho đến và bao gồm cả phiên bản 11g.

Làm cách nào tôi có thể tạo một cột hoạt động như tăng tự động trong Oracle 11g?


3
Bạn có thể tạo một BEFORE INSERTkích hoạt trên bảng và kéo các giá trị ra khỏi chuỗi để tạo tăng tự động
Hunter McMillen

7
Các cột danh tính hiện có sẵn trong Oracle 12c docs.oracle.com/cd/E16655_01/gateways.121/e22508/ mẹo
David Aldridge


Bạn đang sử dụng Oracle RAC? Sử dụng CACHED ở cuối câu lệnh có thể cải thiện hiệu suất. Nếu bạn đang thực hiện nhiều thao tác chèn trong một khoảng thời gian ngắn (và việc đặt hàng không quan trọng đối với bạn), hãy xem xét trình kích hoạt chèn trình tự so le để có thêm lợi ích hiệu suất. Xem: dba-oracle.com/t_rac_proper_ resultence_usage.htmlm
Peeter Kokk

Câu trả lời:


596

Không có thứ gọi là cột "auto_increment" hay "nhận dạng" trong Oracle kể từ Oracle 11g . Tuy nhiên, bạn có thể mô hình hóa nó dễ dàng với trình tự và trình kích hoạt:

Bảng định nghĩa:

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;

Định nghĩa kích hoạt:

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

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

CẬP NHẬT:

IDENTITY cột hiện có sẵn trên Oracle 12c:

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

hoặc chỉ định các giá trị bắt đầu và gia tăng, cũng ngăn chặn mọi chèn vào cột định danh ( GENERATED ALWAYS) (một lần nữa, chỉ Oracle 12c +)

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

Ngoài ra, Oracle 12 cũng cho phép sử dụng một chuỗi làm giá trị mặc định:

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

5
Tôi là một n00b, bạn có thể vui lòng cho tôi biết nơi dept_seqđến từ đâu!
J86

3
TẠO SEQUENCE dept_seq; tạo dept_seq ... giống như một bảng .. nhưng trong trường hợp này chỉ có một số mà bạn có thể tăng với dept_seq.NEXTVAL ... xem trình kích hoạt.
Benjamin Eckstein

Như đã đề cập, mã gốc sẽ thất bại khi gặp một dòng có ID được chỉ định. Nhưng làm thế nào về trường hợp này: Trình kích hoạt sẽ chỉ gán id (tự động) nếu không có id nào được chỉ định rõ ràng trong INSERT. Điều này sẽ thất bại, phải không? Và cách thích hợp để làm điều này là gì?
FanaticD

10
Đối với những người mới nổi tiếng như tôi, phần 'id' của 'new.id' đề cập đến cột 'id' trong bảng trên. 'mới' là một từ dành riêng đề cập đến hàng mới được tạo
Hoppe

2
Bạn không cần phải sử dụng SELECT .. INTOtrong kích hoạt bạn có thể làm :new.id := dept_seq.NEXTVAL;.
MT0

90

SYS_GUIDtrả về một GUID-- một ID duy nhất trên toàn cầu. A SYS_GUIDlà một RAW(16). Nó không tạo ra một giá trị số tăng dần.

Nếu bạn muốn tạo một khóa số tăng dần, bạn sẽ muốn tạo một chuỗi.

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

Sau đó, bạn sẽ sử dụng trình tự đó trong INSERTtuyên bố của mình

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

Hoặc bạn có thể xác định một trình kích hoạt tự động điền giá trị khóa chính bằng chuỗi

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;

Nếu bạn đang sử dụng Oracle 11.1 trở lên, bạn có thể đơn giản hóa trình kích hoạt một chút

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

Nếu bạn thực sự muốn sử dụng SYS_GUID

CREATE TABLE table_name (
  primary_key_column raw(16) default sys_guid() primary key,
  <<other columns>>
)

1
Không gì CACHE 100; in CREATE SEQUENCE name_of_sequence START WITH 1 INCREMENT BY 1 CACHE 100;làm gì?
Angelina

3
CACHE 100: từ khóa tìm nạp 100 số tiếp theo vào bộ nhớ. Thông thường, một SEQUENCE được lưu vào cơ sở dữ liệu bất cứ khi nào giá trị của nó thay đổi, nếu bạn lưu trữ nó, nó sẽ chỉ được lưu và truy xuất nếu các bộ nhớ cache đã hết. Cung cấp cho bạn mức tăng hiệu suất đáng kể, nhưng nếu cơ sở dữ liệu thất bại, bạn sẽ mất tất cả các giá trị được lưu trong bộ nhớ cache mà bạn thậm chí không sử dụng.
Ramazan Polat

2
A SYS_GUID()là a RAW(16), không phải 32.
turbanoff

2
@turbanoff - Bắt tốt. Cập nhật câu trả lời của tôi. Các SYS_GUIDtài liệu tuyên bố raw(32)làm tôi bối rối.
Hang Justin

@JustinCave Tôi đã sử dụng cách tiếp cận của bạn trong việc tạo chuỗi và kích hoạt. Điều gì xảy ra nếu tôi xóa một hàng theo chương trình (java), liệu ID (khóa chính) có được điều chỉnh không?
kittu

52

Trong Oracle 12c trở đi, bạn có thể làm một cái gì đó như,

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

Và trong 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;
/

2
@JonHeller Cá nhân tôi nói IDENTITYví dụ này rõ ràng hơn nhiều trong câu trả lời này.
EpicPandaForce

5
Không WHEN (new.MAP_ID IS NULL)có trong câu trả lời được chấp nhận. Nâng cao.
dcsohl

1
@dcsohl, WHEN ( new.MAP_ID is null)không phải là một mã tốt trong trường hợp này và đã được giải thích trong phần bình luận bởi @ABCade dưới câu trả lời được chấp nhận .. hãy đọc;)
ajmalmhd04

Khi tôi chạy cái này từ CREATE OR REPLACE TRIGGERđến END;, tôi nhận được một cửa sổ "Enter Binds". Nếu tôi nhấp vào "Áp dụng" và không làm gì khác trong cửa sổ đó, rồi chạy ALTER TRIGGERlệnh, tất cả đều tốt, nhưng ước gì có một cách lập trình để thoát khỏi cửa sổ bật lên đó và chạy mọi thứ cùng nhau. Nếu bạn thử nó hoàn toàn, bạn sẽ nhận được PLS-00103: Encountered the symbol 'ALTER'và nó cũng không thích EXECUTE IMMEDIATE(lỗi tương tự, chỉ nói Encountered the symbol 'EXECUTE'thay thế).
vapcguy

Tôi đã nhận được [42000][907] ORA-00907: missing right parenthesiskhi chạy phiên bản cho Oracle 12c trở đi. Bất kỳ ý tưởng ?
belgoros

32

Đây là ba hương vị:

  1. số . Giá trị số tăng đơn giản, ví dụ 1,2,3, ....
  2. HƯỚNG DẪN . định danh chung trên toàn cầu, như một RAWkiểu dữ liệu.
  3. HƯỚNG DẪN (chuỗi) . Tương tự như trên, nhưng là một chuỗi có thể dễ xử lý hơn trong một số ngôn ngữ.

xlà cột danh tính. Thay thế FOOvới tên bảng của bạn trong mỗi ví dụ.

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

cập nhật:

Oracle 12c giới thiệu hai biến thể không phụ thuộc vào trình kích hoạt:

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

Cái đầu tiên sử dụng một chuỗi theo cách truyền thống; thứ hai quản lý giá trị trong nội bộ.


7

Giả sử bạn có nghĩa là một cột như cột nhận dạng SQL Server?

Trong Oracle, bạn sử dụng SEQUENCE để đạt được chức năng tương tự. Tôi sẽ xem nếu tôi có thể tìm thấy một liên kết tốt và đăng nó ở đây.

Cập nhật: có vẻ như bạn đã tìm thấy nó cho mình. Dù sao đây cũng là liên kết: http://www.techonthenet.com/oracle/ Hậuences.php


7

Cơ sở dữ liệu Oracle 12c đã giới thiệu Danh tính, một cột tự động gia tăng (do hệ thống tạo). Trong các phiên bản cơ sở dữ liệu trước đó (cho đến 11g), bạn thường triển khai Danh tính bằng cách tạo Trình tự và Kích hoạt. Từ 12c trở đi, bạn có thể tạo Bảng của riêng mình và xác định cột phải được tạo dưới dạng Danh tính.

Bài viết sau đây giải thích cách sử dụng nó:

Cột định danh - Một mục mới trong Cơ sở dữ liệu Oracle 12c


5
Mặc dù liên kết này có thể trả lời câu hỏi, tốt hơn là bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở nên không hợp lệ nếu trang được liên kết thay đổi.
Cầu

5

TriggerSequencecó thể được sử dụng khi bạn muốn số sê-ri mà bất kỳ ai cũng có thể dễ dàng đọc / ghi nhớ / hiểu. Nhưng nếu bạn không muốn quản lý Cột ID (như emp_id) bằng cách này và giá trị của cột này không đáng kể, bạn có thể sử dụng SYS_GUID()tại Tạo bảng để nhận Tự động tăng như thế này.

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

Bây giờ emp_idcột của bạn sẽ chấp nhận "giá trị định danh duy nhất toàn cầu". bạn có thể chèn giá trị vào bảng bằng cách bỏ qua cột emp_id như thế này.

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

Vì vậy, nó sẽ chèn giá trị duy nhất vào emp_idCột của bạn .


Điều gì xảy ra khi một hàng bị xóa? Liệu SYS_GUID()giá trị id của nó không?
kittu

5

Bắt đầu với Oracle 12c, có hỗ trợ cho các cột Danh tính theo một trong hai cách:

  1. Trình tự + Bảng - Trong giải pháp này, bạn vẫn tạo một chuỗi như bình thường, sau đó bạn sử dụng DDL sau:

    TẠO BẢNG MyTable (ID SỐ DEFAULT MyTable_Seq.NEXTVAL , ...)

  2. Chỉ bảng - Trong giải pháp này không có trình tự được chỉ định rõ ràng. Bạn sẽ sử dụng DDL sau:

    TẠO BẢNG MyTable (SỐ ID TẠO NHƯ NHẬN , ...)

Nếu bạn sử dụng cách đầu tiên thì nó tương thích ngược với cách làm hiện tại. Thứ hai là đơn giản hơn một chút và trực tuyến hơn với các hệ thống RDMS còn lại ngoài kia.


5

nó được gọi là Identity Columns và nó chỉ có sẵn từ oracle Oracle 12c

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

ví dụ về chèn vào Identity Columns như dưới đây

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

Đã tạo 1 hàng.

bạn KHÔNG thể chèn như dưới đây

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

LRI ở dòng 1: ORA-32795: không thể chèn vào cột nhận dạng luôn được tạo

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

LRI ở dòng 1: ORA-32795: không thể chèn vào cột nhận dạng luôn được tạo

liên kết hữu ích


1

Dưới đây là giải pháp hoàn thành xử lý ngoại lệ / lỗi wrt để tăng tự động, giải pháp này tương thích ngược và sẽ hoạt động trên 11g & 12c, đặc biệt nếu ứng dụng đang được sản xuất.

Vui lòng thay thế 'TABLE_NAME' bằng tên bảng thích hợp của bạn

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

0

Đây là cách tôi đã làm điều này trên một bảng và cột hiện có (tên 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;

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;

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;


-1
  create trigger t1_trigger
  before insert on AUDITLOGS
  for each row
   begin
     select t1_seq.nextval into :new.id from dual;
   end;

chỉ tôi phải thay đổi tên bảng (AUDITLOGS) bằng tên bảng của bạn và new.id với new.column_name


-2

Có lẽ chỉ cần thử kịch bản đơn giản này:

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

Kết quả là:

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;

3
Điều này khác với câu trả lời của eugnio như thế nào? Thêm vào đó: bạn không cần các selectphiên bản Oracle hiện đại. Bạn chỉ có thể sử dụng:new.pk := TABLE_PK_SEQ.NEXTVAL
a_horse_with_no_name
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.