Se avessi una tabella con 3 colonne - diciamo A, B e D - e dovessi introdurne una nuova - dì C per sostituire l'attuale posizione di D. Userei il seguente metodo:
- Introduci 2 nuove colonne come C e D2.
- Copia il contenuto di D in D2.
- Elimina D.
- Rinomina D2 in D.
Il nuovo ordine sarebbe A, B, C e D.
Ho pensato che fosse una pratica legittima in quanto (finora) non ha prodotto problemi.
Tuttavia, oggi ho riscontrato un problema quando una funzione che eseguiva un'istruzione sulla stessa tabella restituiva il seguente errore:
table row type and query-specified row type do not match
E il seguente dettaglio:
Query provides a value for a dropped column at ordinal position 13
Ho provato a riavviare PostgreSQL, facendo una VACUUM FULL
e infine cancellando e ricreando la funzione come suggerito qui e qui, ma queste soluzioni non hanno funzionato (a parte il fatto che provano ad affrontare una situazione in cui una tabella di sistema è stata modificata).
Avendo il lusso di lavorare con un database molto piccolo, l'ho esportato, cancellato e poi reimportato e ciò ha risolto il problema con la mia funzione.
Ero consapevole del fatto che non si dovrebbe scherzare con l'ordine naturale delle colonne modificando le tabelle di sistema (sporcandosi le mani pg_attribute
, ecc.) Come visto qui:
È possibile cambiare l'ordine naturale delle colonne in Postgres?
A giudicare dall'errore generato dalla mia funzione, ora mi rendo conto che spostare l'ordine delle colonne con il mio metodo è anche un no-no. Qualcuno può far luce sul perché anche quello che sto facendo è sbagliato?
La versione di Postgres è 9.6.0.
Ecco la funzione:
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
Ho eseguito la ridenominazione / riordino su entrambe le colonne facebook_id
estripe_id
(prima di queste è stata aggiunta una nuova colonna, che è la ragione della ridenominazione, ma non viene toccata da questa query).
Avere le colonne in un certo ordine non ha alcun interesse per l'ordine. Tuttavia, il motivo per cui si pone questa domanda non è preoccupato che una semplice ridenominazione ed eliminazione di una colonna possa innescare problemi reali per qualcuno che utilizza le funzioni in modalità di produzione (come è successo a me stesso).