Вставка в Oracle и получение сгенерированного идентификатора последовательности
У меня есть несколько сырых SQL-запросов для SQL Server, которые используют SCOPE_IDENTITY для получения сгенерированного идентификатора для определенного INSERT сразу после того, как INSERT происходит все за один запуск...
INSERT into Batch(
BatchName,
BatchType,
Source,
Area
) Values (
@strBatchName,
@strType,
@strSource,
@intArea
);
SELECT SCOPE_IDENTITY() BatchID;
Возникает вопрос:
Каков наилучший способ сделать это для базы данных Oracle?
Можно ли это сделать на Oracle через стандартный SQL или мне нужно переключить это, чтобы использовать хранимую процедуру и поместить что-то подобное в тело хранимой процедуры?
Если это должен быть хранимый процесс, то какой де-факто стандартный способ для получения последнего сгенерированного порядкового номера, учитывая, что, вероятно, будут перекрывающиеся выполнения для нескольких потоков, поэтому этому механизму необходимо будет получить право сгенерированный идентификатор и необязательно абсолютный последний сгенерированный идентификатор.
Если два выполняются одновременно, каждый из них должен вернуть правильный сгенерированный идентификатор из каждого соответствующего вызова. Обратите внимание, что я не использую SQL Server "@@IDENTITY" из-за многопоточного характера вызовов.
Я бы предпочел сохранить его как необработанный SQL, если это возможно, так как мне намного легче управлять всеми платформами (один файл, содержащий каждый SQL-блок платформы, разделенный идентификационными тегами СУБД). Сохраненные procs - это немного больше работы для меня, но я могу идти таким образом, если это возможно.
Ответы
Ответ 1
Развернувшись немного на ответах от @Guru и @Ronnis, вы можете скрыть последовательность и сделать ее более похожим на автоинкремент с помощью триггера и выполнить процедуру, которая делает для вас вставку, и возвращает сгенерированный идентификатор как выходной параметр.
create table batch(batchid number,
batchname varchar2(30),
batchtype char(1),
source char(1),
intarea number)
/
create sequence batch_seq start with 1
/
create trigger batch_bi
before insert on batch
for each row
begin
select batch_seq.nextval into :new.batchid from dual;
end;
/
create procedure insert_batch(v_batchname batch.batchname%TYPE,
v_batchtype batch.batchtype%TYPE,
v_source batch.source%TYPE,
v_intarea batch.intarea%TYPE,
v_batchid out batch.batchid%TYPE)
as
begin
insert into batch(batchname, batchtype, source, intarea)
values(v_batchname, v_batchtype, v_source, v_intarea)
returning batchid into v_batchid;
end;
/
Затем вы можете вызвать процедуру вместо простой вставки, например. из аномального блока:
declare
l_batchid batch.batchid%TYPE;
begin
insert_batch(v_batchname => 'Batch 1',
v_batchtype => 'A',
v_source => 'Z',
v_intarea => 1,
v_batchid => l_batchid);
dbms_output.put_line('Generated id: ' || l_batchid);
insert_batch(v_batchname => 'Batch 99',
v_batchtype => 'B',
v_source => 'Y',
v_intarea => 9,
v_batchid => l_batchid);
dbms_output.put_line('Generated id: ' || l_batchid);
end;
/
Generated id: 1
Generated id: 2
Вы можете сделать вызов без явного анонимного блока, например. из SQL * Plus:
variable l_batchid number;
exec insert_batch('Batch 21', 'C', 'X', 7, :l_batchid);
... и используйте переменную привязки :l_batchid
для последующего обращения к сгенерированному значению:
print l_batchid;
insert into some_table values(:l_batch_id, ...);
Ответ 2
В Oracle нет атрибутов автоматической инкрементности для столбца. Вам нужно создать объект SEQUENCE. Вы можете использовать последовательность, например:
insert into table(batch_id, ...) values(my_sequence.nextval, ...)
..., чтобы вернуть следующее число. Чтобы узнать последнюю созданную последовательность nr (в вашем сеансе), вы должны использовать:
my_sequence.currval
Этот сайт содержит несколько полных примеров того, как использовать последовательности.
Ответ 3
Выполнение этого как хранимой процедуры имеет много преимуществ. Вы можете получить последовательность, вставленную в таблицу, используя синтаксис insert into table_name values returning
.
Как
declare
some_seq_val number;
lv_seq number;
begin
some_seq_val := your_seq.nextval;
insert into your_tab (col1, col2, col3)
values (some_seq_val, val2, val3) returning some_seq_val into lv_seq;
dbms_output.put_line('The inserted sequence is: '||to_char(lv_seq));
end;
/
Или просто верните some_seq_val
. В случае, если вы не используете SEQUENCE и не получаете последовательность при некоторых вычислениях, вы можете эффективно использовать returning into
.
Ответ 4
Вы можете использовать приведенный ниже оператор, чтобы вставить идентификатор в переменную.
INSERT INTO YOUR_TABLE(ID) VALUES ('10') returning ID into :Inserted_Value;
Теперь вы можете получить значение, используя приведенный ниже оператор
SELECT :Inserted_Value FROM DUAL;
Ответ 5
Вы можете сделать это с помощью одного оператора - если вы вызываете его из JDBC-подобного соединителя с функциональными возможностями ввода/вывода:
insert into batch(batchid, batchname)
values (batch_seq.nextval, 'new batch')
returning batchid into :l_batchid;
или, как pl-sql script:
variable l_batchid number;
insert into batch(batchid, batchname)
values (batch_seq.nextval, 'new batch')
returning batchid into :l_batchid;
select :l_batchid from dual;