Wenn ich eine Tabelle mit 3 Spalten hätte - sagen Sie A, B und D - und eine neue einführen müsste - sagen Sie C, um die aktuelle Position von D zu ersetzen. Ich würde die folgende Methode anwenden:
- Stellen Sie 2 neue Spalten als C und D2 vor.
- Kopieren Sie den Inhalt von D nach D2.
- Löschen Sie D.
- Benenne D2 in D.
Die neue Reihenfolge wäre A, B, C und D.
Ich hielt dies für eine legitime Praxis, da sie (bisher) keine Probleme verursachte.
Heute bin ich jedoch auf ein Problem gestoßen, als eine Funktion, die eine Anweisung für dieselbe Tabelle ausführt, den folgenden Fehler zurückgab:
table row type and query-specified row type do not match
Und das folgende Detail:
Query provides a value for a dropped column at ordinal position 13
Ich habe versucht, PostgreSQL neu zu starten, ein VACUUM FULL
auszuführen und schließlich die hier und hier vorgeschlagene Funktion zu löschen und neu zu erstellen , aber diese Lösungen haben nicht funktioniert (abgesehen von der Tatsache, dass sie versuchen, eine Situation zu lösen, in der eine Systemtabelle geändert wurde).
Da ich den Luxus hatte, mit einer sehr kleinen Datenbank zu arbeiten, exportierte ich sie, löschte sie und importierte sie erneut. Damit wurde das Problem mit meiner Funktion behoben .
Mir war bewusst, dass man nicht mit der natürlichen Reihenfolge der Spalten herumspielen sollte, indem man Systemtabellen modifiziert (sich die Hände schmutzig machen pg_attribute
usw.), wie hier zu sehen:
Ist es möglich, die natürliche Reihenfolge der Spalten in Postgres zu ändern?
Gemessen an dem Fehler, den meine Funktion verursacht hat, ist mir jetzt klar, dass das Verschieben der Spaltenreihenfolge mit meiner Methode ebenfalls ein Nein-Nein ist. Kann jemand ein bisschen Licht ins Dunkel bringen, warum das, was ich tue, auch falsch ist?
Die Postgres-Version ist 9.6.0.
Hier ist die Funktion:
CREATE OR REPLACE FUNCTION "public"."__post_users" ("facebookid" text, "useremail" text, "username" text) RETURNS TABLE (authentication_code text, id integer, key text, stripe_id text) AS '
-- First, select the user:
WITH select_user AS
(SELECT
users.id
FROM
users
WHERE
useremail = users.email),
-- Second, update the user (if user exists):
update_user AS
(UPDATE
users
SET
authentication_code = GEN_RANDOM_UUID(),
authentication_date = current_timestamp,
facebook_id = facebookid
WHERE EXISTS (SELECT * FROM select_user)
AND
useremail = users.email
RETURNING
users.authentication_code,
users.id,
users.key,
users.stripe_id),
-- Third, insert the user (if user does not exist):
insert_user AS
(INSERT INTO
users (authentication_code, authentication_date, email, key, name, facebook_id)
SELECT
GEN_RANDOM_UUID(),
current_timestamp,
useremail,
GEN_RANDOM_UUID(),
COALESCE(username, SUBSTRING(useremail FROM ''([^@]+)'')),
facebookid
WHERE NOT EXISTS (SELECT * FROM select_user)
RETURNING
users.authentication_code,
users.id,
users.key,
users.stripe_id)
-- Finally, select the authentication code, ID, key and Stripe ID:
SELECT
*
FROM
update_user
UNION ALL
SELECT
*
FROM
insert_user' LANGUAGE "sql" COST 100 ROWS 1
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER
Ich habe die Umbenennung / Neuordnung für beide Spalten facebook_id
und vorgenommen stripe_id
(vor diesen wurde eine neue Spalte hinzugefügt, die der Grund für die Umbenennung ist, aber von dieser Abfrage nicht berührt wird).
Die Spalten in einer bestimmten Reihenfolge zu haben, ist für die Reihenfolge rein uninteressant. Der Grund für diese Frage liegt jedoch in der Befürchtung, dass ein einfaches Umbenennen und Löschen einer Spalte für jemanden, der Funktionen im Produktionsmodus verwendet (wie es mir selbst passiert ist), echte Probleme verursachen kann.
Antworten:
Wahrscheinlicher Fehler in 9.6 und 9.6.1
Das sieht für mich komplett nach einem Bug aus ...
Ich weiß nicht, warum es passiert, aber ich kann bestätigen, dass es passiert. Dies ist das am einfachsten zu findende Setup, das das Problem reproduziert (in Version 9.6.0 und 9.6.1).
Nach diesem Setup funktioniert die nächste Anweisung einfach
An dieser Stelle FALLEN wir eine Spalte:
Diese Änderung löst die nächste Anweisung aus, die einen Fehler generiert
das ist das gleiche wie von @Andy erwähnt:
Das Löschen und Neuerstellen der Funktion löst das Problem NICHT.
VACUUM FULL (die Tabelle oder die gesamte Datenbank) löst das Problem nicht.
Der Fehlerbericht wurde an die entsprechende PostgreSQL-Mailingliste weitergeleitet und wir hatten eine sehr schnelle Antwort :
Version 9.6.2
Am 06.03.2017 kann ich bestätigen, dass ich dieses Verhalten in Version 9.6.2 nicht reproduzieren kann. Das heißt, der Fehler scheint in dieser Version behoben worden zu sein.
AKTUALISIEREN
Per Kommentar von @Jana: "Ich kann bestätigen, dass der Fehler in 9.6.1 vorhanden ist und in 9.6.2 behoben wurde. Die Fehlerbehebung ist auch auf der Website nach der Veröffentlichung von Gres aufgeführt: Fehlerbehebung " Abfrage liefert einen Wert für eine abgelegte Spalte "während INSERT oder UPDATE für eine Tabelle mit einer abgelegten Spalte "
quelle
Ich weiß, dass Sie das wahrscheinlich schon einmal gehört haben, aber das ist eine schreckliche Idee.
SELECT *
Wenn Sie also nicht davon abgehalten werden, etwas zu tun , und wir erkennen an, dass wir Photoshop nur mit Zeilenstruktur und Besessenheit über der Anzeige spielen, lassen Sie uns einige weitere Dinge erklären.
CREATE TABLE
entweder (obwohl es eine viel höhere Priorität wäre)PostgreSQL ist also eine schlechte Anzeigeebene. Auf all das, während es gut
ALTER
funktioniert, solltest du den Drachen nicht tempen. BeideALTER TABLE
und der CAVEAT-Abschnitt erwähnen dies,Und wenn all das nicht genug ist und Sie trotzdem so tun möchten, als wäre dies eine gute Idee, eher eine schreckliche Idee. Dann probiere das,
pg_dump -t
BEGIN
eine TransaktionDROP
die alte Tabelle ganz,RENAME
die temporäre Tabelle zur Prod-Tabelle.COMMIT
Wenn all dies übermäßig klingt, denken Sie daran, dass für das Aktualisieren von Zeilen in der Datenbank ein erneutes Schreiben der Zeilen erforderlich ist (vorausgesetzt, es handelt sich nicht um TOAST . Sie müssen die Daten analysieren und das Tabellenschema neu erstellen, müssen jedoch in beiden Fällen neu schreiben die Reihe. Wenn ich hatte diese Aufgabe zu tun, das ist , wie ich es tun würde.
Aber das alles spricht im Allgemeinen. Niemand hat Ihre Ergebnisse reproduziert.
Sie haben einen Testfall angegeben, den wir nicht ausführen können
Und Sie haben uns nicht die genaue Version mitgeteilt, auf der Sie sich befinden.
quelle
Ich habe diesen Fehler umgangen, indem ich meine Datenbank gesichert und wiederhergestellt habe.
Schritte für Heroku
heroku maintenance:on
heroku pg:backups:capture
heroku pg:backups:restore
heroku restart
heroku maintenance:off
quelle
Ich bin auch auf diesen Bug gestoßen. Für diejenigen, die ihre Datenbank nicht vollständig sichern / wiederherstellen möchten. Wisse, dass das einfache Kopieren der Tabelle funktioniert. Es gibt jedoch keine "magische" Möglichkeit, eine Tabelle zu kopieren. Ich habe es gemacht mit:
Danach müssen Sie Ihre Indizes, Fremdschlüssel und Standardeinstellungen immer noch manuell neu erstellen. Durch diese Neuerstellung des Tisches verschwand der Fehler.
quelle