7
votes

Obtenir une pièce d'identité dans un bloc de transaction postgreSQL

J'essaie d'envelopper toutes mes transactions qui devraient être tout-ou-rien dans commencer code> et commettez code>, mais je ne sais pas comment faire cela dans Des cas comme les suivants.

J'ai 3 tables, une pour les images, une pour albums code>, et une pour les relations entre eux, nommément album_images code>. La manière dont le système fonctionne est qu'un utilisateur peut créer un album et le remplir avec ses images en une seule opération. Le SQL est le suivant: P>

BEGIN;
  INSERT INTO albums [...];  -- Create a new album row
  SELECT id AS album_id FROM albums WHERE [...];  -- Get that rows ID
  -- Now use album_id in the next statement
  INSERT INTO album_images (album_id, image_id) [...];
COMMIT;


0 commentaires

4 Réponses :


1
votes

Postgres fournit une clause "retour" utilisée dans un insert pour récupérer facilement la clé primaire nouvellement créée.

http://www.postgresql.org/docs/8.3/ Interactive / sql-insert.html

Quelques exemples: http://6c62.net/blog/?p=48


2 commentaires

Merci, mais mon problème n'est pas tant d'obtenir cet identifiant, mais avec l'utiliser dans la prochaine déclaration. Que sélectionnez dans mon exemple est le code de travail réel qui retournera la bonne pièce d'identité. Ou ai-je mal compris quelque chose? Ces exemples sont un peu sur ma tête.


Lorsque j'essaie d'utiliser un retour nommé à l'intérieur d'une autre déclaration de la transaction, il jette une "colonne Unkknow" error ... Je ne pense pas que les variables thoses soient partagées dans la transaction.



7
votes

Autre alternative à l'insert ... Clause de retour mentionnée par Cody, vous pouvez utiliser la valeur actuelle de la séquence associée à la colonne ID:

BEGIN;
  INSERT INTO albums [...];
  INSERT INTO album_images (lastval(), image_id) [...];
COMMIT;


12 commentaires

HM, les deux exemples produisent des erreurs de syntaxe à proximité ou à proximité "(" pour moi. Même si l'une d'entre elles fonctionnera finalement, je suppose qu'il n'ya aucun moyen d'utiliser la valeur de album_id de mon Sélectionnez ?


Est lastval spécifique à la transaction ou pourrait-il être modifié par une autre transaction simultanée?


C'est spécifique à la connexion (= session)


@a_horse_with_no_name Pour pouvoir renvoyer la valeur erronée si une autre (partage la connexion) insérée simultanément


@Tobiakinyemi: votre hypothèse est fausse. Utilisation de lastval () directement après une insertion est SA SA SA SA SA SA SA SAFE, tout comme en utilisant Curval () est. Si vous avez une application dans laquelle il est possible que certains code soient un insert et une autre partie effectue une insertion différente à l'aide de la même connexion physique avant que la première transaction ne soit appelée lastval () alors je soutiendrais que votre code est cassé. Mais même dans cette situation, Curval () serait en sécurité supposant que les deux inserts utilisent des tables différentes.


Disons que deux utilisateurs s'inscrivent à votre site Web à exactement en même temps, que leurs transactions ne pouvaient-elles pas être entrecoupées - menant à des insertions corrompues en raison de la condition de race?


Ces deux transactions utiliseraient deux connexions physiques différentes. Vous ne pouvez pas avoir deux transactions indépendantes parallèles sur une seule connexion physique


Donc, lastval () est efficacement spécifique à la transaction (comme une seule transaction peut fonctionner par connexion)?


Non, c'est spécifique à la session. Il renvoie toujours la dernière valeur générée par une séquence. Si vous avez dix insertions dans dix tables, SlastVal retournera celui de l'insert final. S'il vous plaît lire le manuel, c'est tout expliqué là-bas


Donc, ce n'est pas robuste alors, comme cela pourrait renvoyer la mauvaise valeur ...


Si est robuste si vous l'utilisez correctement. C'est comme dire "Supprimer n'est pas robuste parce qu'il pourrait supprimer la mauvaise ligne"


Ce que nous voulons faire est de sélectionner l'identifiant spécifique juste inséré. Lastval est une mise en œuvre hacky, et est sujette à une erreur - simplement en ayant un autre insert simultané ... c'est pourquoi je dis que cela n'est pas robuste. La solution que j'ai affichée n'est pas sujette à ce problème et fonctionne en outre plus logiquement: var a_id = insert_a (...); insertion_a_b (a_id, ...) par opposition à insert_a (...); insertion_a_b (get_the_id_of_the_last_thing_inserted_on_this_con Nection (), ...)



-2
votes

Vous pouvez obtenir l'identifiant de la ligne insérée comme xxx

ceci renvoie l'album_id après l'insertion.


1 commentaires

Plus précisément, l'OP souhaite d'utiliser le ID dans l'instruction suivante de la transaction. Le retour de la clause ne résout pas cela indépendamment.



1
votes

L'accès manuel des séquences n'est pas idéal xxx

renvoyé a été utile, cependant, les 2 autres réponses ne savaient pas / expliquer comment l'appliquer ici < / p>


3 commentaires

" Accessible manuellement des séquences n'est pas une solution robuste" - oui c'est.


@A_HORSE_WITH_NO_NAME a changé mon verbiage


Vous devez au moins supprimer le ; après la CTE pour faire une déclaration correcte.