2011-04-05 60 views
22

我有原始的SQL查询的SQL服务器,该服务器使用SCOPE_IDENTITY检索生成的ID为一个特定的INSERT后立即出现在同一个执行的是INSERT屈指可数...插入到Oracle和检索生成的序列ID

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

SELECT SCOPE_IDENTITY() BatchID; 

现在的问题是:

为Oracle数据库做这件事的最好方法是什么?

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

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

如果两个同时执行然后每个都必须从每个相应的调用返回正确的生成的ID。注意我没有使用SQL Server的“@@ IDENTITY”,因为这种调用的多线程性质。

如果可能,我宁愿将它保留为原始SQL,因为这对我来说跨平台管理(单个文件包含由DBMS标识标记分隔的每个平台的SQL块)要容易得多。存储过程对于我来说有点多管理,但如果这是唯一可行的方法,我可以这样做。

+0

这些是一些很好的答案。现在我正在完成任务,它看起来像另一个使用“包”的图层,将游标设置为“ROWTYPE”,并通过包内的过程或函数*返回一些数据将成为最后一步以结果集的形式返回数据,以便调用者可以执行SELECT,但将需要插入的数据作为参数传递给包函数。新的,所以希望这一切都有道理。 – Allbite 2011-05-09 21:38:32

回答

27

扩展了@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; 
/

然后,您可以调用该过程而不是进行简单插入,例如,从一个不知名的块:

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, ...); 
+0

自从8i以来,由于性能问题,我一直在避免行级触发器,但是我也不得不承认我从未尝试过。它如何执行11g或说10g? – Ronnis 2011-04-09 11:13:55

+0

@Ronnis:没有用足够大的批量插入评论。我没有意识到任何问题,但我认为在某些情况下,上下文切换(必须从双选中选择)可能很重要。而且我认为如果你总是从程序中插入,触发器是毫无意义的,所以这有点过于复杂...... – 2011-04-09 12:42:26

18

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

insert into table(batch_id, ...) values(my_sequence.nextval, ...) 

...返回下一个数字。要找出最后创建序列NR(在你的会话),你可以使用:

my_sequence.currval 

This site对如何使用序列几个完整的例子。

11

做为存储过程确实有很多优点。您可以使用语法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

你甚至不需要那么多步骤;没有一点声明'some_seq',你可以'插入你的_tab(col1,col2,col3)值(your_seq.next_val,val2,val3),将col1返回到lv_seq;'。另外值得注意的是,您可以将返回值直接放入'out'参数中。 – 2011-04-05 22:03:21

9

您可以使用下面的语句获取插入的标识给一个变量类似的东西。

INSERT INTO YOUR_TABLE(ID) VALUES ('10') returning ID into :Inserted_Value; 

现在你可以使用下面的语句检索值

SELECT :Inserted_Value FROM DUAL; 
0

你可以用一条语句做到这一点 - 假设你是从一个类似JDBC连接器,称这是输入/输出参数的功能:

insert into batch(batchid, batchname) 
values (batch_seq.nextval, 'new batch') 
returning batchid into :l_batchid; 

,或作为PL-SQL脚本:

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;