Знакомые с MySQL программисты при первом знакомстве с СУРБД Oracle, вероятно, удивятся отсутствию в ней такой приятной возможности, как создание
В MySQL эти поля создаются буквально на лету:
В такую таблицу можно вставлять записи, не задумываясь об автоматической генерации первичного ключа id, который будет увеличиваться на 1 для каждой новой записи. Иными словами, можно выполнить запрос вида
и для каждой из созданных записей в случае MySQL будет автоматически вычислен id.
В Oracle
Как видно из объявления, последовательность начинается с 1 (конечно, при необходимости, можно задать другое значение), шаг последовательности также равен 1, последовательность не имеет максимального значения.
Теперь при создании записей в таблице нам необходимо присваивать полю id текущее значение счетчика-последовательности (или следующее значение счетчика в зависимости от реализации). Это можно сделать двумя способами - создать триггер, отслеживающий создание записей в таблице и присваивающий полю
Рассмотрим оба варианта.
В теле триггера мы проверяем, что
Использование хитрого
В данном случае новое значение счетчика вычисляется при каждом вызове
PS. Созданные последовательности и триггеры легко удалить, поэтому не бойтесь с ними работать.
auto_increment
полей, то есть полей, численное значение которых автоматически увеличивается при создании новых записей. Как правило, auto_increment
поля используются как primary key
- первичные ключи для таблиц.В MySQL эти поля создаются буквально на лету:
CREATE TABLE users(
id MEDIUMINT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL, PRIMARY KEY (id)
);
В такую таблицу можно вставлять записи, не задумываясь об автоматической генерации первичного ключа id, который будет увеличиваться на 1 для каждой новой записи. Иными словами, можно выполнить запрос вида
INSERT INTO userns(name) VALUES ("sterx"),("alex"),("kime");
и для каждой из созданных записей в случае MySQL будет автоматически вычислен id.
В Oracle
auto_increment
поля создаются несколько иначе, используются так называемые последовательности (sequence
), или, другими словами, счетчики. Создадим последовательность:CREATE SEQUENCE users_seq
START WITH 1
INCREMENT BY 1
NOMAXVALUE;
Как видно из объявления, последовательность начинается с 1 (конечно, при необходимости, можно задать другое значение), шаг последовательности также равен 1, последовательность не имеет максимального значения.
Теперь при создании записей в таблице нам необходимо присваивать полю id текущее значение счетчика-последовательности (или следующее значение счетчика в зависимости от реализации). Это можно сделать двумя способами - создать триггер, отслеживающий создание записей в таблице и присваивающий полю
id
значение счетчика, либо в самой команде INSERT
использовать значение счетчика для задания значения id
. Использование триггера с одной стороны усложняет реализацию, с другой стороны упрощает команды INSERT
, поэтому выбор способа установки id оставлю на усмотрение читателя.Рассмотрим оба варианта.
Использование триггера
create or replace trigger users_id_trg
before insert on users
for each row
begin
if :new.id is null then
select users_seq.nextval into :new.id from dual;
end if;
end;
В теле триггера мы проверяем, что
id
новой записи не установлен пользователем, так как по своим причинам пользователь может захотеть установить значение id
самостоятельно, не полагаясь на триггер. Если это не так - вычисляется новое значение счетчика и id
устанавливается автоматически.Использование хитрого INSERT
INSERT INTO users (id, name) VALUES (users_seq.nextval, 'sterx');
В данном случае новое значение счетчика вычисляется при каждом вызове
INSERT
, значение поля id вычисляется соответственно в самом теле команды без триггера.PS. Созданные последовательности и триггеры легко удалить, поэтому не бойтесь с ними работать.
DROP SEQUENCE users_seq;
DROP TRIGGER users_id_trg;
Здравствуйте!
ОтветитьУдалитьВо-первых спасибо за простой и понятный пост!
единственное что не совсем понятно что такое dual в теле триггера
Здравствуйте!
ОтветитьУдалитьСпасибо за комментарий.
dual - это служебная таблица Oracle Database, она состоит из одного поля dummy и содержит одну запись со значением X. Это ее свойство, как правило, используется для возврата значений псевдо-колонок (констант, sysdate и т.п.):
select 'Вася' from dual;
select 2+3 as s from dual;
select sysdate from dual;
Вместо dual можно использовать любую другую таблицу с одной записью, однако, для таких целей принято использовать именно dual.
Вообще говоря, dual - это обычная таблица, которой владеет пользователь SYS, соответственно, она может быть изменена - чего по понятным причинам крайне не рекомендуется делать. Это просто эталонная таблица с одним полем и одной записью.
Здравствуйте.
ОтветитьУдалитьСогласен с Dzmitry, простая статья, все написано понятным языком, однако в моем варианте триггера auto_increment не используются последовательность. Его реализацию я описал в своем блоге.
http://k-maxim.ru/bazy-dannyx/auto_increment-v-subd-oracle-database.html
Apache47,
ОтветитьУдалитьДумаю методика Голобурдина реализована лучше, т.к в твоем варианте приходится проводить операции по сравнению. А тут просто переменная.
Всё правильно, можно и так и так, НО:
ОтветитьУдалитьЕсли у вас в таблицу заносится много записей, многими юзерами, с бесчисленных коннектов, то сиквенс - единственная возможность сохранить уникальность без использования блокировок и всякой лабуды.
А если это простая справочная таблица с занесением записей админом от случая к случаю, то используйте не просто макс+1, а каунт+1 (желательно с проверкой значения ид на уникальность - тогда точно последовательность ид сохранится идеально). Но это вариант для мазохистов...
не работают ваши скрипты.
ОтветитьУдалитьCREATE OR REPLACE
TRIGGER TRIGGER1
BEFORE INSERT ON NEWS
for each row
BEGIN
if :new.id is null then
select sequence1.nextval into :new.id from dual;
end if;
--NULL;
END;
Error: ORA-06552: PL/SQL: Compilation unit analysis terminated
ORA-06553: PLS-320: the declaration of the type of this expression is incomplete or malformed
И что такое вобще это new.id?
ОтветитьУдалитьпохоже тригер не создался только потому, что в именах полей таблицы были зарезервированыне слова типа DATE.
ОтветитьУдалитьСпасибо. Кратко. Ясно. Очень помогли!
ОтветитьУдалитьОтлично, рад, что помог!
Удалитьв 12с уже есть автоинкремент
ОтветитьУдалитьСпасибо! Взял за основу прием с триггером. Но я обошелся без создания последовательности (sequence). Я просто беру МАХ значение id и прибавляю к нему +1.
ОтветитьУдалитьcreate or replace trigger users_id_trg
before insert on users
for each row
begin
if :new.id is null then
select MAX(id)+1 into :new.id from users;
end if;
end;
That is very nice
ОтветитьУдалитьThat is very nice!
ОтветитьУдалить