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.