2011-04-05 51 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;