J'ai une table:
CREATE TABLE names (id serial, name varchar(20))
Je veux le "dernier identifiant inséré" de cette table, sans utiliser RETURNING id
Lors de l'insertion. Il semble y avoir une fonction CURRVAL()
, mais je ne comprends pas comment l'utiliser.
J'ai essayé avec:
SELECT CURRVAL() AS id FROM names_id_seq
SELECT CURRVAL('names_id_seq')
SELECT CURRVAL('names_id_seq'::regclass)
mais aucun ne fonctionne. Comment puis-je utiliser currval()
pour obtenir le dernier identifiant inséré?
Si vous créez une colonne comme serial
PostgreSQL crée automatiquement une séquence pour cela.
Le nom de la séquence est généré automatiquement et est toujours tablename_columnname_seq, dans votre cas, la séquence sera nommée names_id_seq
.
Après l'insertion dans le tableau, vous pouvez appeler currval()
avec ce nom de séquence:
postgres=> CREATE TABLE names in schema_name (id serial, name varchar(20));
CREATE TABLE
postgres=> insert into names (name) values ('Arthur Dent');
INSERT 0 1
postgres=> select currval('names_id_seq');
currval
---------
1
(1 row)
postgres=>
Au lieu de coder en dur le nom de la séquence, vous pouvez également utiliser pg_get_serial_sequence()
à la place:
select currval(pg_get_serial_sequence('names', 'id'));
De cette façon, vous n'avez pas besoin de vous fier à la stratégie de nommage utilisée par Postgres.
Ou si vous ne voulez pas du tout utiliser le nom de la séquence, utilisez lastval()
C'est directement de débordement de pile
Comme cela a été souligné par @a_horse_with_no_name et @Jack Douglas, currval ne fonctionne qu'avec la session en cours. Donc, si vous êtes d'accord avec le fait que le résultat pourrait être affecté par une transaction non validée d'une autre session, et que vous voulez toujours quelque chose qui fonctionnera entre les sessions, vous pouvez utiliser ceci:
SELECT last_value FROM your_sequence_name;
Utilisez le lien vers SO pour plus d'informations.
De documentation Postgres cependant, il est clairement indiqué que
C'est une erreur d'appeler lastval si nextval n'a pas encore été appelé dans la session en cours.
Donc, je suppose à strictement parler afin d'utiliser correctement currval ou last_value pour une séquence entre les sessions, vous auriez besoin de faire quelque chose comme ça?
SELECT setval('serial_id_seq',nextval('serial_id_seq')-1);
En supposant, bien sûr, que vous ne disposerez pas d'un insert ou de toute autre manière d'utiliser le champ série dans la session en cours.
Vous devez appeler nextval
pour cette séquence dans cette session avant currval
:
create sequence serial;
select nextval('serial');
nextval
---------
1
(1 row)
select currval('serial');
currval
---------
1
(1 row)
vous ne pouvez donc pas trouver le "dernier identifiant inséré" dans la séquence à moins que insert
ne soit effectué dans la même session (une transaction peut être annulée mais pas la séquence)
comme indiqué dans la réponse de a_horse, create table
avec une colonne de type serial
créera automatiquement une séquence et l'utilisera pour générer la valeur par défaut de la colonne, donc un insert
accède normalement à nextval
implicitement:
create table my_table(id serial);
NOTICE: CREATE TABLE will create implicit sequence "my_table_id_seq" for
serial column "my_table.id"
\d my_table
Table "stack.my_table"
Column | Type | Modifiers
--------+---------+-------------------------------------------------------
id | integer | not null default nextval('my_table_id_seq'::regclass)
insert into my_table default values;
select currval('my_table_id_seq');
currval
---------
1
(1 row)
Il y a donc quelques problèmes avec ces différentes méthodes:
Currval n'obtient que la dernière valeur générée dans la session en cours - ce qui est génial si vous n'avez rien d'autre qui génère des valeurs, mais dans les cas où vous pourriez appeler un déclencheur et/ou faire avancer la séquence plus d'une fois dans la transaction en cours, c'est ne va pas retourner la valeur correcte. Ce n'est pas un problème pour 99% des gens - mais c'est quelque chose qu'il faut prendre en considération.
La meilleure façon d'obtenir l'identifiant unique attribué après une opération d'insertion est d'utiliser la clause RETURNING. L'exemple ci-dessous suppose que la colonne liée à la séquence est appelée "id":
insert into table A (cola,colb,colc) values ('val1','val2','val3') returning id;
Notez que l'utilité de la clause RETURNING va bien au-delà de la simple obtention de la séquence, car elle permettra également:
Renvoie les valeurs qui ont été supprimées:
supprimer du tableau A où id> 100 renvoyant *
Renvoie les lignes modifiées après une MISE À JOUR:
mettre à jour la table A définir X = 'y' où blah = 'blech' renvoyant *
Utilisez le résultat d'une suppression pour une mise à jour:
AVEC A comme (supprimer * du tableau A comme identifiant de retour) mise à jour B set supprimé = vrai où id dans (sélectionner l'identifiant dans A);
Vous devez utiliser GRANT
sur le schéma, comme ceci:
GRANT USAGE ON SCHEMA schema_name to user;
et
GRANT ALL PRIVILEGES ON schema_name.sequence_name TO user;
Si vous voulez obtenir la valeur des séquences sans avoir appelé nextval()
, et sans avoir à modifier la séquence, j'ai créé une fonction PL/pgSQL pour la gérer: Trouver la valeur de tous séquences de base de données
J'ai dû exécuter une requête malgré l'utilisation de SQLALchemy car je n'ai pas réussi à utiliser currval.
nextId = db.session.execute("select last_value from <table>_seq").fetchone()[0] + 1
C'était un python flask + projet postgresql.
Dans PostgreSQL 11.2, vous pouvez traiter la séquence comme une table, semble-t-il:
Exemple si vous avez une séquence nommée: 'names_id_seq'
select * from names_id_seq;
last_value | log_cnt | is_called
------------+---------+-----------
4 | 32 | t
(1 row)
Cela devrait vous donner le dernier identifiant inséré (4 dans ce cas), ce qui signifie que la valeur actuelle (ou la valeur qui devrait être utilisée pour l'identifiant suivant) devrait être 5.