Ich bin auf das Problem gestoßen, dass meine Primärschlüsselfolge nicht mit meinen Tabellenzeilen synchronisiert ist.
Das heißt, wenn ich eine neue Zeile einfüge, wird ein doppelter Schlüsselfehler angezeigt, da die im seriellen Datentyp implizierte Sequenz eine bereits vorhandene Nummer zurückgibt.
Dies scheint darauf zurückzuführen zu sein, dass beim Importieren / Wiederherstellen die Sequenz nicht ordnungsgemäß beibehalten wird.
postgresql
primary-key
database-sequence
meleyal
quelle
quelle
Antworten:
Quelle - Ruby Forum
quelle
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
kann verwendet werden, um falsche Annahmen über den Sequenznamen zu vermeiden. Dies setzt die Sequenz auf einmal zurück:Oder genauer:
Dieses Formular kann jedoch leere Tabellen nicht korrekt verarbeiten, da max (id) null ist und Sie auch nicht 0 setzen können, da es außerhalb des Bereichs der Sequenz liegen würde. Eine Problemumgehung besteht darin, auf die
ALTER SEQUENCE
Syntax zurückzugreifen, d. H.Dies
ALTER SEQUENCE
ist jedoch von begrenztem Nutzen, da der Sequenzname und der Neustartwert keine Ausdrücke sein können.Es scheint, dass die beste Allzwecklösung darin besteht,
setval
false als dritten Parameter aufzurufen , um den "nächsten zu verwendenden Wert" anzugeben:Dies erfüllt alle meine Kriterien:
Beachten Sie schließlich, dass dies
pg_get_serial_sequence
nur funktioniert, wenn die Sequenz der Spalte gehört. Dies ist der Fall, wenn die inkrementierende Spalte alsserial
Typ definiert wurde. Wenn die Sequenz jedoch manuell hinzugefügt wurde, muss sichergestellt werden, dass sieALTER SEQUENCE .. OWNED BY
auch ausgeführt wird.Wenn also der
serial
Typ für die Tabellenerstellung verwendet wurde, sollte dies alles funktionieren:Aber wenn Sequenzen manuell hinzugefügt wurden:
quelle
setval()
setzt den aktuellen Wert undnextval()
gibt bereits den aktuellen Wert +1 zurück.Der kürzeste und schnellste Weg:
tbl_id
Alsserial
Tabellenspaltetbl
wird aus der Sequenz gezeichnettbl_tbl_id_seq
(dies ist der automatische Standardname).Wenn Sie den Namen der angehängten Sequenz nicht kennen (die nicht in der Standardform vorliegen muss), verwenden Sie
pg_get_serial_sequence()
:Hier gibt es keinen Fehler nach dem anderen. Pro Dokumentation:
Meine kühne Betonung.
Wenn die Tabelle leer sein kann und in diesem Fall tatsächlich bei 1 beginnen soll:
Wir können nicht einfach das 2-Paremater-Formular verwenden und damit beginnen,
0
da die untere Grenze der Sequenzen standardmäßig 1 ist (sofern nicht angepasst).Parallelität
Es gibt noch keine Verteidigung gegen gleichzeitige Sequenzaktivitäten oder Schreibvorgänge in die Tabelle in den obigen Abfragen. Wenn dies relevant ist, können Sie die Tabelle im exklusiven Modus sperren . Es verhindert, dass gleichzeitige Transaktionen eine höhere Zahl schreiben, während Sie versuchen, eine Synchronisierung durchzuführen. (Außerdem werden harmlose Schreibvorgänge vorübergehend blockiert, ohne die maximale Anzahl zu beeinträchtigen.)
Es werden jedoch keine Clients berücksichtigt, die möglicherweise zuvor Sequenznummern ohne Sperren für die Haupttabelle abgerufen haben (was passieren kann). Um dies ebenfalls zu berücksichtigen, erhöhen Sie nur den aktuellen Wert der Sequenz, verringern Sie ihn niemals. Es mag paranoid erscheinen, aber das stimmt mit der Art der Sequenzen und der Verteidigung gegen Parallelitätsprobleme überein.
quelle
EXECUTE format()
(wie @ EB.'s) ist eine wesentliche Funktion! Wie kann dieser Mangel an Standardbibliothek in PostgreSQL behoben werden?Dadurch werden alle öffentlichen Sequenzen zurückgesetzt, ohne dass Annahmen über Tabellen- oder Spaltennamen getroffen werden. Getestet auf Version 8.4
quelle
substring(column_default, '''(.*)''')
stattdessen verwendettable_name || '_' || column_name || '_seq'
. Funktioniert perfekt.quote_literal
undquote_ident
-Funktionen oder vorzugsweise dieformat
Funktion sollten hier wirklich verwendet werden.substring(column_default from 'nextval\(''(.+)''::regclass\)')
den Sequenznamen explizit abgerufen. Lief wie am Schnürchen.substring(column_default, '''(.*)''') instead of table_name || '_' || column_name || '_seq'
ALTER SEQUENCE Sequenzname RESTART WITH (SELECT max (id) FROM Tabellenname);Funktioniert nichtVon @tardate Antwort kopiert:
quelle
Dieser Befehl ändert nur den automatisch generierten Schlüsselsequenzwert in postgresql
Anstelle von Null können Sie eine beliebige Zahl eingeben, von der aus Sie die Sequenz neu starten möchten.
Standardsequenzname wird
"TableName_FieldName_seq"
. Wenn beispielsweise Ihr Tabellenname"MyTable"
und Ihr Feldname lautet"MyID"
, lautet Ihr Sequenzname"MyTable_MyID_seq"
.Diese Antwort entspricht der Antwort von @ murugesanponappan, es liegt jedoch ein Syntaxfehler in seiner Lösung vor. Sie können keine Unterabfrage
(select max()...)
imalter
Befehl verwenden. Damit Sie entweder einen festen numerischen Wert verwenden müssen oder anstelle einer Unterabfrage eine Variable verwenden müssen.quelle
Alle Sequenzen zurücksetzen, keine Annahmen über Namen, außer dass der Primärschlüssel jeder Tabelle "id" ist:
quelle
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 );
Diese Funktionen sind mit Gefahren behaftet, wenn Sequenznamen, Spaltennamen, Tabellennamen oder Schemanamen lustige Zeichen wie Leerzeichen, Satzzeichen und dergleichen enthalten. Ich habe folgendes geschrieben:
Sie können es für eine einzelne Sequenz aufrufen, indem Sie die OID übergeben. Es wird die höchste Nummer zurückgegeben, die von einer Tabelle verwendet wird, in der die Sequenz standardmäßig verwendet wird. oder Sie können es mit einer Abfrage wie dieser ausführen, um alle Sequenzen in Ihrer Datenbank zurückzusetzen:
Mit einem anderen Qual können Sie nur die Sequenz in einem bestimmten Schema zurücksetzen und so weiter. Wenn Sie beispielsweise Sequenzen im "öffentlichen" Schema anpassen möchten:
Beachten Sie, dass Sie aufgrund der Funktionsweise von setval () keine 1 zum Ergebnis hinzufügen müssen.
Abschließend muss ich warnen, dass einige Datenbanken Standardeinstellungen zu haben scheinen, die mit Sequenzen verknüpft sind, sodass die Systemkataloge nicht über vollständige Informationen verfügen. Dies passiert, wenn Sie solche Dinge in psqls \ d sehen:
Beachten Sie, dass der Aufruf von nextval () in dieser Standardklausel zusätzlich zur Umwandlung von :: regclass eine :: text-Umwandlung enthält. Ich denke, das liegt daran, dass Datenbanken aus alten PostgreSQL-Versionen pg_dump'ed werden. Was passieren wird ist, dass die obige Funktion sequence_max_value () eine solche Tabelle ignoriert. Um das Problem zu beheben, können Sie die DEFAULT-Klausel neu definieren, um direkt auf die Sequenz ohne die Besetzung zu verweisen:
Dann zeigt psql es richtig an:
Sobald Sie dies behoben haben, funktioniert die Funktion für diese Tabelle sowie für alle anderen, die möglicherweise dieselbe Sequenz verwenden, ordnungsgemäß.
quelle
newmax := r.max::bigint;
damit es für mich richtig funktioniert.'SELECT max(' || quote_ident(colname) || ') FROM '
=>'SELECT max(' || quote_ident(colname) || '::bigint) FROM '
Beachten Sie die hinzugefügte::bigint
Besetzung in der dynamisch erstellten Abfrage.Noch ein plpgsql - wird nur zurückgesetzt, wenn
max(att) > then lastval
Wenn Sie die Zeile auch kommentieren,
--execute format('alter sequence
wird die Liste angezeigt, ohne dass der Wert zurückgesetzt wirdquelle
Setzen Sie alle Sequenzen von public zurück
quelle
Ich schlage vor, diese Lösung im Postgres-Wiki zu finden. Es aktualisiert alle Sequenzen Ihrer Tabellen.
Verwendung (aus dem Postgres-Wiki):
Beispiel:
Originalartikel (auch mit Fix für Sequenzbesitz) hier
quelle
Einige wirklich harte Antworten hier, ich gehe davon aus, dass es zu der Zeit, als dies gefragt wurde, wirklich schlecht war, da viele Antworten von hier für Version 9.3 nicht funktionieren. Die Dokumentation seit Version 8.0 bietet eine Antwort auf genau diese Frage:
Wenn Sie sich um Sequenznamen kümmern müssen, bei denen zwischen Groß- und Kleinschreibung unterschieden wird, gehen Sie folgendermaßen vor:
quelle
Dieses Problem tritt bei mir auf, wenn das Entity Framework zum Erstellen der Datenbank verwendet und die Datenbank dann mit Anfangsdaten versehen wird. Dadurch stimmt die Sequenz nicht überein.
Ich habe es gelöst, indem ich ein Skript erstellt habe, das nach dem Seeding der Datenbank ausgeführt werden soll:
quelle
MAX("Id") + 1
bei mir am besten funktioniert wenn die sequenz = maximal ist.Meine Version verwendet die erste, mit einigen Fehlerprüfungen ...
quelle
RAISE WARNING
für mich identifiziert haben.Alles zusammenfügen
wird die
id'
Reihenfolge der angegebenen Tabelle festlegen (wie dies normalerweise bei Django erforderlich ist).quelle
bevor ich den Code noch nicht ausprobiert hatte: Im Folgenden poste ich die Version für den SQL-Code für Klaus- und user457226-Lösungen, die auf meinem PC [Postgres 8.3] funktionierten, mit nur ein paar kleinen Anpassungen für den Klaus und meine Version für den Benutzer457226 eine.
Klaus Lösung:
user457226 Lösung:
quelle
Überprüfen Sie alle Sequenzen in der öffentlichen Schemafunktion erneut
quelle
Um alle Sequenzen auf 1 neu zu starten, verwenden Sie:
quelle
Die Klaus-Antwort ist die nützlichste, die für einen kleinen Fehler ausgeführt wird: Sie müssen DISTINCT in die select-Anweisung einfügen.
Wenn Sie jedoch sicher sind, dass keine Tabellen- und Spaltennamen für zwei verschiedene Tabellen gleichwertig sein können, können Sie auch Folgendes verwenden:
Dies ist eine Erweiterung der user457226-Lösung für den Fall, dass ein interessierter Spaltenname nicht 'ID' ist.
quelle
Wenn dieser Fehler beim Laden benutzerdefinierter SQL-Daten zur Initialisierung angezeigt wird, können Sie dies auf folgende Weise vermeiden:
Anstatt zu schreiben:
Entfernen Sie den
id
(Primärschlüssel) aus den AnfangsdatenDies hält die Postgres-Sequenz synchron!
quelle
Diese Antwort ist eine Kopie von Mauro.
quelle
Ich habe eine Stunde lang versucht, die Antwort von djsnowsill für die Arbeit mit einer Datenbank mithilfe von Tabellen und Spalten mit gemischten Groß- und Kleinschreibung zu finden, und bin dann dank eines Kommentars von Manuel Darveau schließlich auf die Lösung gestoßen, aber ich dachte, ich könnte es für alle etwas klarer machen:
Dies hat den Vorteil von:
Um dies zu erklären, bestand das Problem darin, dass
pg_get_serial_sequence
Zeichenfolgen erforderlich sind, um herauszufinden, worauf Sie sich beziehen. Wenn Sie also Folgendes tun:Dies wird erreicht, indem
''%1$I''
in der Formatzeichenfolge verwendet wird,''
ein Apostroph1$
bedeutet erstes Argument undI
bedeutet in Anführungszeichenquelle
quelle
Hässlicher Hack, um es mit etwas Shell-Magie zu beheben, keine großartige Lösung, könnte aber andere mit ähnlichen Problemen inspirieren :)
quelle
Versuchen Sie es erneut .
UPDATE: Wie in den Kommentaren erwähnt, war dies eine Antwort auf die ursprüngliche Frage.
quelle
SELECT setval...
macht JDBC bork, also hier ist eine Java-kompatible Möglichkeit, dies zu tun:quelle
Eine Methode zum Aktualisieren aller Sequenzen in Ihrem Schema, die als ID verwendet werden:
quelle
Führen Sie einfach den folgenden Befehl aus:
quelle
Hier gibt es viele gute Antworten. Ich hatte das gleiche Bedürfnis nach dem Neuladen meiner Django-Datenbank.
Aber ich brauchte:
Dies scheint dem Bedarf der ursprünglichen Anfrage sehr ähnlich zu sein.
Dank Baldiry und Mauro bin ich auf dem richtigen Weg.
Um die Änderungen auszuführen und zu sehen, führen Sie sie aus:
Kehrt zurück
quelle