Як створити ідентифікатор за допомогою AUTO_INCREMENT в Oracle?


422

Здається, що в Oracle немає концепції AUTO_INCREMENT, аж до версії 11g.

Як я можу створити стовпчик, який веде себе як автоматичне збільшення в Oracle 11g?


3
Ви можете створити BEFORE INSERTтригер на столі і витягнути значення з послідовності, щоб створити автоматичне збільшення
Hunter McMillen

7
Стовпці посвідчення особи тепер доступні в Oracle 12c docs.oracle.com/cd/E16655_01/gateways.121/e22508/…
Девід Олдрідж


Ви використовуєте Oracle RAC? Використання CACHED в кінці заяви може підвищити продуктивність. Якщо ви робите багато вставок за короткий період (і замовлення для вас не важливо), врахуйте поступовий тригер вставки послідовності для додаткових переваг продуктивності. Дивіться: dba-oracle.com/t_rac_proper_sequence_usage.htm
Peeter Kokk

Відповіді:


596

У Oracle немає такого поняття, як "auto_increment" або "identitet", як у Oracle 11g . Однак ви можете легко моделювати її за допомогою послідовності та тригера:

Визначення таблиці:

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;

Визначення тригера:

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

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

ОНОВЛЕННЯ:

IDENTITY тепер доступний у Oracle 12c:

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

або вказати початкові та прирістні значення, також запобігаючи будь-якій вставці в стовпець ідентичності ( GENERATED ALWAYS) (знову ж, лише Oracle 12c +)

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

Крім того, Oracle 12 також дозволяє використовувати послідовність як значення за замовчуванням:

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
Я n00b, скажіть, будь ласка, звідки dept_seq!
J86

3
СТВОРИТИ ПОСЛІДУ dept_seq; створює dept_seq ... як таблиця .. але в цьому випадку його єдине число, яке ви можете збільшити за допомогою dept_seq.NEXTVAL ... див. тригер.
Бенджамін Екштейн

Як вже було сказано, початковий код не зможе зіткнутися з рядком із вказаним ідентифікатором. А як щодо цього випадку: тригер призначить ідентифікатор (автоматично), лише якщо в INSERT не вказано явно вказаний ідентифікатор. Це не вдасться, правда? І який правильний спосіб це зробити?
FanaticD

10
Для новачків-оракул, як я, частина "id" частини "new.id" відноситься до стовпця "id" у таблиці вище. 'new' - це зарезервоване слово, яке посилається на новий створений рядок
Hoppe

2
Вам не потрібно використовувати SELECT .. INTOв тригері, який ви можете просто зробити :new.id := dept_seq.NEXTVAL;.
MT0

90

SYS_GUIDповертає GUID - глобально унікальний ідентифікатор. А SYS_GUID- це RAW(16). Він не генерує збільшення числа.

Якщо ви хочете створити наростаючий числовий ключ, вам потрібно створити послідовність.

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

Тоді ви або використовуєте цю послідовність у своєму INSERTвикладі

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

Або ви можете визначити тригер, який автоматично заповнює значення первинного ключа, використовуючи послідовність

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 або новішу версію, ви можете трохи спростити тригер

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

Якщо ви дійсно хочете використовувати SYS_GUID

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

1
Що робить CACHE 100; in CREATE SEQUENCE name_of_sequence START WITH 1 INCREMENT BY 1 CACHE 100;?
Анджеліна

3
CACHE 100: ключове слово отримує наступні 100 цифр у пам'яті. Зазвичай ПОСІБНІСТЬ зберігається в базі даних кожного разу, коли її значення змінюється, якщо ви кешуєте її, вона буде збережена та отримана, лише якщо кешовані файли вичерпані. Дає вам значне збільшення продуктивності, але якщо база даних не працює, ви втрачаєте всі кешовані значення, які ви навіть не використовували.
Рамазан Полат

2
А SYS_GUID()- це RAW(16), а не 32.
турбанов

2
@turbanoff - Хороший улов. Оновлено мою відповідь. SYS_GUIDДокументація оголошує raw(32)який мене збентежив.
Джастін Печера

@JustinCave Я використовував ваш підхід для створення послідовності та тригера. Що робити, якщо програмно видалити рядок (java), чи буде також скориговано ідентифікатор (первинний ключ)?
kittu

52

В Oracle 12c і далі ви можете зробити щось на кшталт,

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

-- 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 Я особисто кажу, що IDENTITYприклад набагато зрозуміліший у цій відповіді.
EpicPandaForce

5
WHEN (new.MAP_ID IS NULL)Чи не в загальноприйнятому відповідь. Отримано.
dcsohl

1
@dcsohl, WHEN ( new.MAP_ID is null)це не гарний код у цьому випадку, і це вже пояснено в розділі коментарів @ABCade під прийнятою відповіддю. Прочитайте;)
ajmalmhd04,

Коли я запускаю це від CREATE OR REPLACE TRIGGERдо END;, я отримую вікно "Введіть зв'язки". Якщо я натискаю "Застосувати" і більше нічого не роблю у цьому вікні, а потім запускаю ALTER TRIGGERкоманду, все добре, але хочете, щоб був спосіб програмно позбутися цього спливаючого вікна і запустити все разом. Якщо ви спробуєте його взагалі, ви отримаєте PLS-00103: Encountered the symbol 'ALTER'і це не подобається EXECUTE IMMEDIATE(та сама помилка, просто каже це Encountered the symbol 'EXECUTE'замість).
vapcguy

Я отримав [42000][907] ORA-00907: missing right parenthesisпри запуску версії для Oracle 12c і далі. Будь-яка ідея?
belgoros

32

Ось три аромати:

  1. числовий . Просте число, що збільшується, наприклад, 1,2,3, ....
  2. ДОГОВІР . глобальний універсальний ідентифікатор як RAWтип даних.
  3. GUID (рядок) . Те саме, що вище, але як рядок, який може бути простішим для обробки в деяких мовах.

x- стовпець посвідчення. Замініть FOOназви таблиці у кожному з прикладів.

-- 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 представляє два варіанти, які не залежать від тригерів:

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

Перший використовує послідовність традиційним способом; другий керує значенням внутрішньо.


7

Якщо припустити, ви маєте на увазі стовпець, як стовпець ідентичності SQL Server?

В Oracle ви використовуєте ПОСЛІДНІСТЬ для досягнення тієї ж функціональності. Я побачу, чи зможу знайти гарне посилання та опублікую його тут.

Оновлення: схоже, ви самі знайшли його. Ось посилання все одно: http://www.techonthenet.com/oracle/sequences.php


7

Oracle Database 12c представив ідентичність, стовпчик автоматичного збільшення (генерований системою). У попередніх версіях бази даних (до 11 г) ви зазвичай реалізуєте ідентичність, створюючи послідовність і тригер. Починаючи з 12с, ви можете створити власну таблицю та визначити стовпець, який має бути сформований як ідентичність.

Наступна стаття пояснює, як ним користуватися:

Стовпці особи - новий запис у Oracle Database 12c


5
Хоча це посилання може відповісти на питання, краще включити сюди суттєві частини відповіді та надати посилання для довідки. Відповіді лише на посилання можуть стати недійсними, якщо пов’язана сторінка зміниться.
Міст

5

Triggerі Sequenceможе використовуватися, коли потрібно серіалізований номер, який кожен може легко прочитати / запам'ятати / зрозуміти. Але якщо ви не хочете керувати таким чином стовпцем ідентифікаторів (наприклад, emp_id), а значення цього стовпця не дуже значне, ви можете скористатися програмою " SYS_GUID()Створення таблиці", щоб отримати подібне автоматичне збільшення.

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

Тепер ваш emp_idстовпець прийме "глобально унікальне значення ідентифікатора". ви можете вставити значення в таблицю, ігноруючи подібний стовпець emp_id.

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

Отже, воно додасть унікальну цінність вашому emp_idстовпцю.


Що станеться, коли рядок буде видалено? Чи буде також SYS_GUID()його значення id?
kittu

5

Починаючи з Oracle 12c, існує підтримка стовпців Identity одним із двох способів:

  1. Послідовність + Таблиця - у цьому рішенні ви все одно створюєте послідовність, як зазвичай, тоді використовуєте наступний DDL:

    СТВОРИТИ ТАБЛИЦЮ MyTable (ID номер НЕБЕЗПЕЧЕНО MyTable_Seq.NEXTVAL , ...)

  2. Тільки таблиця - У цьому рішенні жодна послідовність прямо не вказана. Ви б використовували таку DDL:

    СТВОРИТИ ТАБЛИЦЮ MyTable (Ідентифікаційний номер, згенерований як ідентичність , ...)

Якщо ви використовуєте перший спосіб, він є сумісним назад із існуючим способом виконання дій. Друга трохи простіша і більш влучна з рештою систем RDMS там.


5

він називається, Identity Columnsі він доступний тільки від Oracle Oracle 12c

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

Приклад вставлення в Identity Columnsяк нижче

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

Створено 1 ряд.

ви НЕ можете вводити, як нижче

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

ПОМИЛКА в рядку 1: ORA-32795: не вдається вставити в генерований стовпець завжди ідентичності

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

ПОМИЛКА в рядку 1: ORA-32795: не вдається вставити в генерований стовпець завжди ідентичності

корисне посилання


1

Ось повне рішення wrt виключення / обробка помилок для автоматичного збільшення, це рішення є сумісним назад і працюватиме на 11g та 12c, зокрема, якщо програма використовується у виробництві.

Замініть "TABLE_NAME" на відповідну назву таблиці

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

Ось так я це зробив у існуючій таблиці та стовпці (з іменем 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

oracle має послідовності І стовпці ідентичності в 12c

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

Я знайшов це, але не впевнений, що таке rdb 7 http://www.oracle.com/technetwork/products/rdb/0307-identity-column-128126.pdf


Корисна інформація та цікаве порівняння продуктивності. Використовувати стовпці ІДЕНТИЧНОСТІ краще, ніж використовувати TRIGGER для ПОСЛУГИ
ygoe

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

тільки я повинен просто змінити назву таблиці (AUDITLOGS) з назвою таблиці та new.id на new.column_name


-2

Можливо, просто спробуйте цей простий сценарій:

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

Результат:

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
Чим це відрізняється від відповіді eugnio? Плюс: вам не потрібні selectсучасні версії Oracle. Ви можете просто скористатися:new.pk := TABLE_PK_SEQ.NEXTVAL
a_horse_with_no_name
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.