web-dev-qa-db-fra.com

Insertion dans Oracle et récupération de l'ID de séquence généré

J'ai une poignée de requêtes SQL brutes pour SQL Server qui utilisent SCOPE_IDENTITY pour récupérer l'ID généré pour un INSERT spécifique immédiatement après que INSERT se soit produit en une seule exécution…

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

SELECT SCOPE_IDENTITY() BatchID;

La question est: 

Quelle est la meilleure façon de faire cela pour une base de données Oracle?

Cela peut-il être fait sur Oracle via SQL standard ou dois-je changer pour utiliser une procédure stockée et placer quelque chose de similaire dans le corps de la procédure stockée? 

S'il doit s'agir d'une procédure stockée, quelle est la méthode standard de facto pour extraire le dernier numéro de séquence généré, en prenant en compte le fait que des exécutions se chevaucheront probablement sur plusieurs threads; ce mécanisme devra donc extraire l'ID généré correctement et pas nécessairement le dernier identifiant absolu généré. 

Si deux sont exécutés simultanément, chacun doit renvoyer l'ID généré correctement pour chaque appel respectif. Notez que je n’utilise pas le code «@@ IDENTITY» de SQL Server en raison de la nature multithread des appels.

Dans la mesure du possible, je préférerais le conserver sous forme de code SQL brut, car cela me facilite beaucoup la gestion sur plusieurs plates-formes (un seul fichier contenant le bloc SQL de chaque plate-forme, séparé par des balises d’identification de SGBD). Les procédures stockées sont un peu plus de travail pour moi, mais je peux le faire si c'est le seul moyen possible.

26
Allbite

En développant un peu les réponses de @Guru et @Ronnis, vous pouvez masquer la séquence et lui donner l’apparence d’une incrémentation automatique à l’aide d’un déclencheur; paramètre.

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;
/

Vous pouvez ensuite appeler la procédure au lieu de faire une insertion simple, par exemple. d'un bloc anormal:

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

Vous pouvez effectuer l’appel sans bloc anonyme anonyme, par exemple. de SQL * Plus:

variable l_batchid number;
exec insert_batch('Batch 21', 'C', 'X', 7, :l_batchid);

... et utilisez la variable d'association :l_batchid pour faire référence à la valeur générée par la suite:

print l_batchid;
insert into some_table values(:l_batch_id, ...);
29
Alex Poole

Il n'y a pas de fonctionnalité d'incrémentation automatique dans Oracle pour une colonne. Vous devez créer un objet SEQUENCE. Vous pouvez utiliser la séquence comme:

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

... pour retourner le numéro suivant. Pour connaître la dernière séquence créée (dans votre session), utilisez:

my_sequence.currval

Ce site contient plusieurs exemples complets sur l’utilisation des séquences.

20
Ronnis

Le faire en tant que procédure stockée présente de nombreux avantages. Vous pouvez obtenir la séquence insérée dans la table en utilisant la syntaxe insert into table_name values returning.

Comme:

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;
/

Ou retournez simplement some_seq_val. Si vous ne vous servez pas de SEQUENCE et si vous arrivez à la suite de certains calculs, vous pouvez utiliser returning into efficacement.

11
Guru

Vous pouvez utiliser l’instruction ci-dessous pour obtenir l’ID inséré en une variable semblable à une variable.

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

Maintenant, vous pouvez récupérer la valeur en utilisant l'instruction ci-dessous

SELECT :Inserted_Value FROM DUAL;
8
Sarath Avanavu

Vous pouvez le faire avec une seule instruction - en supposant que vous l'appelez à partir d'un connecteur de type JDBC avec une fonctionnalité de paramètres d'entrée/sortie:

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

ou, en tant que script 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;
1
Franjo Markovic