插入Oracle并检索生成的序列ID

All*_*ite 28 sql oracle stored-procedures identity-column scope-identity

我有一些SQL Server的原始SQL查询,它们使用SCOPE_IDENTITY在一次执行INSERT后立即检索特定INSERT的生成ID ...

INSERT into Batch(
BatchName,
BatchType,
Source,
Area
) Values (
@strBatchName,
@strType,
@strSource,
@intArea
);

SELECT SCOPE_IDENTITY() BatchID;
Run Code Online (Sandbox Code Playgroud)

问题是:

对Oracle数据库执行此操作的最佳方法是什么?

这可以通过标准SQL在Oracle上完成,还是我必须将其切换为使用存储过程并在存储过程的主体中放置类似的东西?

如果它必须是存储过程,那么检索最后生成的序列号的事实上的标准方法是什么,注意考虑在多个线程上可能存在重叠执行,因此该机制需要检索正确生成的ID和不一定是绝对最后生成的ID.

如果两个同时执行,则每个必须从每个相应的呼叫返回正确的生成ID.注意我没有使用SQL Server的"@@ IDENTITY",因为调用的多线程特性.

如果可能的话,我宁愿将其保留为原始SQL,因为我更容易跨平台管理(包含由DBMS识别标签分隔的每个平台的SQL块的单个文件).存储过程对我来说要管理的工作要多一点,但如果这是唯一可能的话,我可以这样做.

Ale*_*ole 32

对@Guru和@Ronnis的答案进行了扩展,您可以隐藏序列并使其看起来更像是使用触发器的自动增量,并且有一个为您执行插入操作的过程并将生成的ID作为输出返回参数.

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;
/
Run Code Online (Sandbox Code Playgroud)

然后,您可以调用该过程而不是执行普通插入,例如从一个无聊的块中:

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
Run Code Online (Sandbox Code Playgroud)

您可以在没有显式匿名块的情况下进行调用,例如从SQL*Plus中调用:

variable l_batchid number;
exec insert_batch('Batch 21', 'C', 'X', 7, :l_batchid);
Run Code Online (Sandbox Code Playgroud)

...然后使用bind变量:l_batchid引用生成的值:

print l_batchid;
insert into some_table values(:l_batch_id, ...);
Run Code Online (Sandbox Code Playgroud)


Ron*_*nis 20

Oracle中没有用于列的自动递增功能.您需要创建一个SEQUENCE对象.你可以使用如下序列:

insert into table(batch_id, ...) values(my_sequence.nextval, ...)
Run Code Online (Sandbox Code Playgroud)

...返回下一个号码.要查找最后创建的序列nr(在您的会话中),您将使用:

my_sequence.currval
Run Code Online (Sandbox Code Playgroud)

该站点有几个关于如何使用序列的完整示例.

  • currval 仅在会话中调用 nextval 后才有效,并且该值按会话保留。如果会话 A 调用 nextval 并获取 ID = 10,而会话 B 调用 nextval 1000 次,则如果调用 currval,会话 A 仍将获取 ID = 10。 (2认同)

Gur*_*uru 13

将其作为存储过程执行确实具有很多优点.您可以使用语法获取插入表中的序列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;
/
Run Code Online (Sandbox Code Playgroud)

或者只是回来some_seq_val.如果您没有使用SEQUENCE,并且在某些计算中到达序列,您可以returning into有效地利用它.

  • 你甚至不需要那么多步骤; 没有点声明`some_seq`,你可以`插入你的_tab(col1,col2,col3)值(your_seq.next_val,val2,val3)将col1返回到lv_seq;`.另外值得注意的是,您可以将返回值直接放入`out`参数中. (4认同)

Sar*_*avu 8

您可以使用以下语句将插入的Id添加到类似变量的内容中.

INSERT INTO  YOUR_TABLE(ID) VALUES ('10') returning ID into :Inserted_Value;
Run Code Online (Sandbox Code Playgroud)

现在,您可以使用以下语句检索值

SELECT :Inserted_Value FROM DUAL;
Run Code Online (Sandbox Code Playgroud)

  • 那你为什么不也“出示”声明呢?答案必须完整。 (4认同)