PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Fonction PostgreSQL pour le dernier ID inséré

( tl;dr :goto option 3 :INSERT with RETURNING )

Rappelez-vous que dans postgresql, il n'y a pas de concept "id" pour les tables, juste des séquences (qui sont généralement mais pas nécessairement utilisées comme valeurs par défaut pour les clés primaires de substitution, avec le pseudo-type SERIAL).

Si vous souhaitez obtenir l'identifiant d'une ligne nouvellement insérée, vous pouvez procéder de plusieurs manières :

Option 1 :CURRVAL(<sequence name>); .

Par exemple :

  INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
  SELECT currval('persons_id_seq');

Le nom de la séquence doit être connu, c'est vraiment arbitraire; dans cet exemple nous supposons que la table persons a un id colonne créée avec le SERIAL pseudo-type. Pour éviter de dépendre de cela et pour vous sentir plus propre, vous pouvez utiliser à la place pg_get_serial_sequence :

  INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
  SELECT currval(pg_get_serial_sequence('persons','id'));

Mise en garde :currval() ne fonctionne qu'après un INSERT (qui a exécuté nextval() ), dans la même session .

Option 2 :LASTVAL();

Ceci est similaire au précédent, sauf que vous n'avez pas besoin de spécifier le nom de la séquence :il recherche la séquence modifiée la plus récente (toujours à l'intérieur de votre session, même mise en garde que ci-dessus).

Les deux CURRVAL et LASTVAL sont totalement sécurisés simultanément. Le comportement de la séquence dans PG est conçu pour que différentes sessions n'interfèrent pas, il n'y a donc aucun risque de conditions de concurrence (si une autre session insère une autre ligne entre mon INSERT et mon SELECT, j'obtiens toujours ma valeur correcte).

Cependant ils ont un problème potentiel subtil. Si la base de données a un TRIGGER (ou RULE) qui, lors de l'insertion dans persons table, fait quelques insertions supplémentaires dans d'autres tables... puis LASTVAL nous donnera probablement la mauvaise valeur. Le problème peut même arriver avec CURRVAL , si les insertions supplémentaires sont faites dans les mêmes persons table (c'est beaucoup moins courant, mais le risque existe toujours).

Option 3 :INSERT avec RETURNING

INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John') RETURNING id;

C'est le moyen le plus propre, le plus efficace et le plus sûr d'obtenir l'identifiant. Il ne présente aucun des risques du précédent.

Désavantages? Presque aucun :vous devrez peut-être modifier la façon dont vous appelez votre instruction INSERT (dans le pire des cas, peut-être que votre API ou votre couche de base de données ne s'attend pas à ce qu'un INSERT renvoie une valeur) ; ce n'est pas du SQL standard (on s'en fout); il est disponible depuis Postgresql 8.2 (décembre 2006...)

Conclusion :Si vous le pouvez, optez pour l'option 3. Ailleurs, préférez la 1.

Remarque :toutes ces méthodes sont inutiles si vous avez l'intention d'obtenir le dernier identifiant inséré globalement (pas nécessairement par votre session). Pour cela, vous devez recourir à SELECT max(id) FROM table (bien sûr, cela ne lira pas les insertions non validées d'autres transactions).

Inversement, vous ne devriez jamais utilisez SELECT max(id) FROM table au lieu de l'une des 3 options ci-dessus, pour obtenir l'identifiant qui vient d'être généré par votre INSERT déclaration, parce que (en dehors des performances) ce n'est pas simultané en toute sécurité :entre votre INSERT et votre SELECT une autre session a peut-être inséré un autre enregistrement.