web-dev-qa-db-fra.com

currval n'a pas encore été défini pour cette session, comment obtenir des séquences multi-sessions?

Mon objectif est d'insérer automatiquement un champ de clé primaire lors de l'insertion d'une nouvelle ligne dans le tableau.

Comment faire passer une séquence de session en session dans PostgreSQL?

 doubleemploi@hanbei:/home/yves$ psql -d test
 Mot de passe : 
 psql (8.4.13)
 Saisissez « help » pour l''aide.

 test=> create sequence test001 start 10;
 CREATE SEQUENCE
 test=> select currval('test001');
 ERREUR:  la valeur courante (currval) de la séquence « test00 » n''est pas encore définie dans cette session
 --- current value not yet defined this session (???)
 test=> select setval('test001', 10);
 setval 
 --------
      10
 (1 ligne)

 test=> select currval('test00');
  currval 
 ---------
       10
 (1 ligne)

 test=> \q
 test@hanbei:/home/yves$ psql -d test
 Mot de passe : 
 psql (8.4.13)
 Saisissez « help » pour l''aide.

 test=> select currval('test001');
 ERREUR:  la valeur courante (currval) de la séquence « test00 » n''est pas encore définie dans cette session
26
MUY Belgium

Cela peut être plus simple que vous ne le pensez ...

Mon objectif est d'insérer automatiquement un champ de clé primaire lors de l'insertion d'une nouvelle ligne dans le tableau.

Définissez simplement la valeur par défaut de la colonne:

ALTER TABLE tbl ALTER COLUMN tbl_id SET DEFAULT nextval('my_seq'::regclass);

Ou encore plus simple, créez la table avec un type serial pour la clé primaire pour commencer:

CREATE TABLE tbl(
  tbl_id serial PRIMARY KEY
 ,col1 txt
  -- more columns
);

Il crée une séquence dédiée et définit automatiquement la valeur par défaut pour tbl_id.

Par ici tbl_id est automatiquement affectée à la prochaine valeur de la séquence jointe si vous ne la mentionnez pas dans INSERT. Fonctionne avec any session, simultanée ou non.

INSERT INTO tbl(col1) VALUES ('foo');

Si vous voulez le nouveau tbl_id retour pour en faire quelque chose:

INSERT INTO tbl(col1) VALUES ('foo') RETURNING tbl_id;
15
Erwin Brandstetter

currval renverra la dernière valeur générée pour la séquence dans la session en cours. Donc, si une autre session génère une nouvelle valeur pour la séquence, vous pouvez toujours récupérer la dernière valeur générée par VOTRE session, en évitant les erreurs.

Mais, pour obtenir la dernière valeur générée sur toutes les sessions, vous pouvez utiliser ce qui précède:

SELECT last_value FROM your_sequence_name;

Attention, si la valeur a été utilisée par une autre session avec une transaction non validée (ou abandonnée) et que vous utilisez cette valeur comme référence, vous pouvez obtenir une erreur. Généralement, les gens ont juste besoin du currval ou même du retour de setval.

85
MatheusOl

Je donnerai une réponse pratique à ce sujet. Mon serveur de base de données est utilisé par mes programmes et mon terminal psql; il y a donc plusieurs sessions. actuellement je suis dans mon terminal psql:

fooserver=> select currval('fusion_id_seq');
ERROR:  currval of sequence "fusion_id_seq" is not yet defined in this session
fooserver=> select nextval('fusion_id_seq');
 nextval 
---------
  320032
(1 row)

fooserver=> select currval('fusion_id_seq');
 currval 
---------
  320032
(1 row)

Il semble que vous ne puissiez voir les valeurs que dans votre propre session. Cela affectera également le currval d'une autre session. Ceci est probablement lié au multi-threading du serveur pour isoler différentes sessions. Le compteur (série en psql) est un objet partagé. À mon avis, cette session devrait être en mesure d'obtenir la valeur actuelle du compteur tant que le compteur est correctement verrouillé pour garantir qu'un seul thread (session) puisse l'incrémenter (opération atomique). Mais je peux me tromper ici (pas un expert en écriture de serveur de base de données).

6
Kemin Zhou

En fait nextval fera avancer la séquence et renverra la nouvelle valeur, ce serait donc la réponse à votre question.

currval renverra la valeur la plus récemment obtenue avec nextval pour la séquence spécifiée (cela pourrait cependant échouer s'il n'y avait pas nextval utilisé dans la session en cours).

2
Jalal

Ce problème semble être intermittent, pour des raisons de cohérence, utilisez CTE pour obtenir la séquence insérée pour la session en cours

AVEC AS inséré (INSERT INTO notifn_main (notifn_dt, stat_id) SELECT now (), 22 FROM notifn RETURNING id) SELECT id from inséré INTO tmp_id;

1
Sandeep naik