J'ai rencontré le problème que ma séquence de clé primaire n'est pas synchronisée avec mes lignes de table.
Autrement dit, lorsque j'insère une nouvelle ligne, j'obtiens une erreur de clé en double car la séquence impliquée dans le type de données série renvoie un nombre qui existe déjà.
Cela semble provenir de l'import / restauration qui ne maintient pas la séquence correctement.
Réponses:
Source - Ruby Forum
la source
SELECT setval('your_table_id_seq', coalesce((select max(id)+1 from your_table), 1), false);
SELECT setval('your_seq',(SELECT GREATEST(MAX(your_id)+1,nextval('your_seq'))-1 FROM your_table))
pg_get_serial_sequence
peut être utilisé pour éviter toute hypothèse incorrecte sur le nom de la séquence. Cela réinitialise la séquence en une seule fois:Ou plus précisément:
Cependant, ce formulaire ne peut pas gérer correctement les tables vides, car max (id) est nul, et vous ne pouvez pas non plus définir val 0 car il serait hors de portée de la séquence. Une solution pour cela consiste à recourir à la
ALTER SEQUENCE
syntaxe, à savoirMais
ALTER SEQUENCE
son utilité est limitée car le nom de séquence et la valeur de redémarrage ne peuvent pas être des expressions.Il semble que la meilleure solution polyvalente soit d'appeler
setval
avec false comme 3e paramètre, ce qui nous permet de spécifier la "prochaine valeur à utiliser":Cela coche toutes mes cases:
Enfin, notez que cela
pg_get_serial_sequence
ne fonctionne que si la séquence appartient à la colonne. Ce sera le cas si la colonne d'incrémentation a été définie comme unserial
type, mais si la séquence a été ajoutée manuellement, il est nécessaire de s'assurer qu'elleALTER SEQUENCE .. OWNED BY
est également effectuée.c'est-à-dire si le
serial
type a été utilisé pour la création de table, cela devrait fonctionner:Mais si des séquences ont été ajoutées manuellement:
la source
setval()
définit la valeur actuelle etnextval()
renverra déjà la valeur actuelle +1.Le moyen le plus court et le plus rapide :
tbl_id
étant laserial
colonne du tableautbl
, tirée de la séquencetbl_tbl_id_seq
(qui est le nom automatique par défaut).Si vous ne connaissez pas le nom de la séquence jointe (qui ne doit pas nécessairement être sous la forme par défaut), utilisez
pg_get_serial_sequence()
:Il n'y a pas d'erreur off-by-one ici. Par documentation:
Accentuation sur moi.
Si la table peut être vide et commencer à partir de 1 dans ce cas:
Nous ne pouvons pas simplement utiliser le formulaire à 2 paramètres et commencer par
0
parce que la limite inférieure des séquences est 1 par défaut (sauf si personnalisé).Accès simultané
Il n'y a pas encore de défense contre l'activité de séquence simultanée ou d'écriture dans la table dans les requêtes ci-dessus. Si cela est pertinent, vous pouvez verrouiller la table en mode exclusif. Il empêche les transactions simultanées d'écrire un nombre plus élevé pendant que vous essayez de vous synchroniser. (Il bloque également temporairement les écritures inoffensives ne jouant pas avec le nombre maximal.)
Mais il ne prend pas en compte les clients qui peuvent avoir récupéré à l'avance des numéros de séquence sans verrou sur la table principale (ce qui peut arriver). Pour permettre cela aussi, augmentez uniquement la valeur actuelle de la séquence, ne la diminuez jamais. Cela peut sembler paranoïaque, mais cela est conforme à la nature des séquences et à la défense contre les problèmes de concurrence.
la source
EXECUTE format()
(comme @ EB.'s) est une fonction essentielle! Comment corriger ce manque de bibliothèque standard dans PostgreSQL ????Cela réinitialisera toutes les séquences du public en ne faisant aucune hypothèse sur les noms de table ou de colonne. Testé sur la version 8.4
la source
substring(column_default, '''(.*)''')
place detable_name || '_' || column_name || '_seq'
. Marche parfaitement.quote_literal
etquote_ident
, ou de préférence laformat
fonction, devraient vraiment être utilisées ici.substring(column_default from 'nextval\(''(.+)''::regclass\)')
de saisir explicitement le nom de la séquence. A fonctionné comme un charme.substring(column_default, '''(.*)''') instead of table_name || '_' || column_name || '_seq'
ALTER SEQUENCE nom_séquence RESTART WITH (SELECT max (id) FROM nom_table);Ça ne marche pas.Copié de la réponse @tardate:
la source
Cette commande ne modifie que la valeur de séquence de touches générée automatiquement dans postgresql
Au lieu de zéro, vous pouvez mettre n'importe quel nombre à partir duquel vous souhaitez redémarrer la séquence.
le nom de séquence par défaut sera
"TableName_FieldName_seq"
. Par exemple, si votre nom de table est"MyTable"
et votre nom de champ est"MyID"
, alors votre nom de séquence sera"MyTable_MyID_seq"
.Cette réponse est la même que la réponse de @ murugesanponappan, mais il y a une erreur de syntaxe dans sa solution. vous ne pouvez pas utiliser de sous-requête
(select max()...)
dans laalter
commande. De sorte que soit vous devez utiliser une valeur numérique fixe, soit vous devez utiliser une variable à la place de la sous-requête.la source
Réinitialiser toutes les séquences, pas d'hypothèses sur les noms sauf que la clé primaire de chaque table est "id":
la source
pg_get_serial_sequence(''"' || tablename || '"''
EXECUTE format( 'SELECT setval(pg_get_serial_sequence(%L, %L), coalesce(max(id),0) + 1, false) FROM %I;', $1,$2,$1 );
Ces fonctions sont lourdes de dangers lorsque les noms de séquence, les noms de colonne, les noms de table ou les noms de schéma ont des caractères amusants tels que des espaces, des signes de ponctuation, etc. J'ai écrit ceci:
Vous pouvez l'appeler pour une seule séquence en lui passant l'OID et il renverra le nombre le plus élevé utilisé par n'importe quelle table qui a la séquence par défaut; ou vous pouvez l'exécuter avec une requête comme celle-ci, pour réinitialiser toutes les séquences de votre base de données:
En utilisant un qual différent, vous pouvez réinitialiser uniquement la séquence dans un certain schéma, etc. Par exemple, si vous souhaitez ajuster des séquences dans le schéma "public":
Notez qu'en raison du fonctionnement de setval (), vous n'avez pas besoin d'ajouter 1 au résultat.
Pour terminer, je dois avertir que certaines bases de données semblent avoir des valeurs par défaut liées aux séquences de manière à ne pas laisser les catalogues système en avoir toutes les informations. Cela se produit lorsque vous voyez des choses comme celle-ci dans \ d de psql:
Notez que l'appel nextval () dans cette clause par défaut a un cast :: text en plus du cast :: regclass. Je pense que cela est dû au fait que les bases de données sont pg_dump'ed d'anciennes versions de PostgreSQL. Ce qui se passera, c'est que la fonction sequence_max_value () ci-dessus ignorera une telle table. Pour résoudre le problème, vous pouvez redéfinir la clause DEFAULT pour faire référence à la séquence directement sans le cast:
Ensuite, psql l'affiche correctement:
Dès que vous avez corrigé cela, la fonction fonctionne correctement pour cette table ainsi que pour toutes les autres qui pourraient utiliser la même séquence.
la source
newmax := r.max::bigint;
pour le faire fonctionner correctement pour moi.'SELECT max(' || quote_ident(colname) || ') FROM '
=>'SELECT max(' || quote_ident(colname) || '::bigint) FROM '
remarquez le::bigint
cast ajouté dans la requête de construction dynamique.Encore un autre plpgsql - ne se réinitialise que si
max(att) > then lastval
commenter la ligne
--execute format('alter sequence
donnera également la liste, sans réinitialiser la valeurla source
Réinitialiser toutes les séquences du public
la source
Je suggère cette solution trouvée sur le wiki postgres. Il met à jour toutes les séquences de vos tables.
Comment utiliser (à partir du wiki postgres):
Exemple:
Article d'origine (également avec correctif pour la propriété de la séquence) ici
la source
Quelques réponses vraiment hardcore ici, je suppose que c'était vraiment mauvais au moment où cela a été demandé, car beaucoup de réponses d'ici ne fonctionnent pas pour la version 9.3. La documentation depuis la version 8.0 fournit une réponse à cette question même:
De plus, si vous devez prendre soin des noms de séquence sensibles à la casse, c'est comme ça que vous le faites:
la source
Ce problème se produit avec moi lorsque j'utilise le framework d'entité pour créer la base de données et ensuite amorcer la base de données avec les données initiales, cela crée une incompatibilité de séquence.
Je l'ai résolu en créant un script à exécuter après l'amorçage de la base de données:
la source
MAX("Id") + 1
cela fonctionne le mieux pour moi lorsque la séquence est = au maximum.Ma version utilise la première, avec quelques vérifications d'erreurs ...
la source
RAISE WARNING
identifié pour moi.Mettre tous ensemble
va corriger la
id'
séquence de la table donnée (comme cela est généralement nécessaire avec django par exemple).la source
avant je n'avais pas encore essayé le code: dans ce qui suit je poste la version du code sql pour les solutions Klaus et user457226 qui fonctionnaient sur mon pc [Postgres 8.3], avec juste quelques petits ajustements pour le Klaus one et de ma version pour l'utilisateur457226 un.
Solution Klaus:
solution user457226:
la source
Revérifiez toutes les séquences dans la fonction de schéma public
la source
Pour redémarrer toutes les séquences à 1, utilisez:
la source
La réponse de Klaus est la plus utile, sauf pour un petit manque: vous devez ajouter DISTINCT dans l'instruction select.
Cependant, si vous êtes sûr qu'aucun nom de table + colonne ne peut être équivalent pour deux tables différentes, vous pouvez également utiliser:
qui est une extension de la solution user457226 pour le cas où un nom de colonne intéressé n'est pas 'ID'.
la source
Si vous voyez cette erreur lorsque vous chargez des données SQL personnalisées pour l'initialisation, une autre façon d'éviter cela est:
Au lieu d'écrire:
Supprimer la
id
(clé primaire) des données initialesCela permet de synchroniser la séquence Postgres!
la source
Cette réponse est une copie de mauro.
la source
J'ai passé une heure à essayer d'obtenir la réponse de djsnowsill pour travailler avec une base de données à l'aide de tables et de colonnes à cas mixtes, puis j'ai finalement trouvé la solution grâce à un commentaire de Manuel Darveau, mais j'ai pensé que je pourrais le rendre un peu plus clair pour tout le monde:
Cela a l'avantage de:
Pour expliquer, le problème était qu'il
pg_get_serial_sequence
fallait des chaînes pour comprendre à quoi vous faites référence, donc si vous le faites:Ceci est réalisé en utilisant
''%1$I''
dans la chaîne de format,''
fait une apostrophe1$
signifie premier argument, etI
signifie entre guillemetsla source
la source
Hack laid pour le réparer en utilisant de la magie du shell, pas une excellente solution mais pourrait inspirer d'autres personnes avec des problèmes similaires :)
la source
Essayez de réindexer .
MISE À JOUR: Comme indiqué dans les commentaires, c'était en réponse à la question initiale.
la source
SELECT setval...
rend JDBC bork, voici donc une façon compatible Java de le faire:la source
Une méthode pour mettre à jour toutes les séquences de votre schéma qui sont utilisées comme ID:
la source
Exécutez simplement la commande ci-dessous:
la source
Il y a beaucoup de bonnes réponses ici. J'avais le même besoin après avoir rechargé ma base de données Django.
Mais j'avais besoin de:
Ce besoin semble très similaire à celui de la demande initiale.
Merci à Baldiry et Mauro m'a mis sur la bonne voie.
Ensuite, pour exécuter et voir les modifications s'exécuter:
Retour
la source