La cosa cruciale da capire è che le tabelle SQL non hanno un ordinamento . L'ordine delle righe che vedi quando SELECT
senza un ORDER BY
rimane lo stesso solo perché è più veloce per il database ottenerli in quell'ordine rispetto a un altro ordine. PostgreSQL restituirà le righe in questo ordine solo quando esegui una scansione sequenziale sulla tabella; se può utilizzare un indice per la query, generalmente otterrai le righe in un altro ordine.
Potresti trovare questa risposta che ho scritto in precedenza informativo.
In PostgreSQL, UPDATE
s in righe possono spostarli in una posizione diversa all'interno della tabella, modificando l'ordine in cui vengono restituiti. Così può il processo di autovacuum in background e varie altre operazioni come VACUUM
e CLUSTER
.
Quindi non devi mai fare affidamento sull'ordine "predefinito" per qualsiasi cosa. Se vuoi dare alle righe un qualche tipo di ordine, loro devono avere una chiave su cui ordinarli.
Se hai creato una tabella senza una chiave e ora ti rendi conto che dovrebbe averne una, potresti essere in grado di recuperare dalla situazione utilizzando il ctid
colonna di sistema. non fare affidamento su questo per l'uso in produzione, è una colonna interna al sistema visibile agli utenti solo per scopi diagnostici e di ripristino di emergenza. Innanzitutto, verifica se l'ordine fisico su disco è effettivamente l'ordine desiderato:
SELECT row_number() OVER () AS mytable_id, *
FROM mytable
ORDER BY ctid;
In tal caso, puoi aggiungere una nuova colonna chiave preimpostata su una chiave con incremento automatico applicata nell'ordine delle righe su disco. Ci sono due modi per farlo. Il più sicuro è:
BEGIN;
LOCK TABLE mytable IN ACCESS EXCLUSIVE MODE;
ALTER TABLE mytable RENAME TO mytable_old;
CREATE TABLE mytable (id SERIAL PRIMARY KEY, LIKE mytable_old INCLUDING ALL);
INSERT INTO mytable
SELECT row_number() OVER () AS id, *
FROM mytable_old
ORDER BY ctid;
SELECT setval('mytable_id_seq', (SELECT max(id)+1 FROM mytable));
COMMIT;
quindi una volta che sei sicuro di essere soddisfatto dei risultati, DROP TABLE mytable_old;
. Guarda questa demo:http://sqlfiddle.com/#!12/2cb99/2
Un modo semplice e veloce, ma meno sicuro, è semplicemente creare la colonna e fare affidamento su PostgreSQL che riscrive la tabella dall'inizio alla fine:
ALTER TABLE mytable ADD COLUMN mytable_id SERIAL PRIMARY KEY;
Non c'è assolutamente nessuna garanzia che PostgreSQL assegnerà gli ID in ordine, anche se in pratica lo farà. Guarda questa demo di SQLFiddle.
Tieni presente che quando usi una SEQUENCE
(che è ciò che è un SERIAL
colonna crea) ci sono alcuni comportamenti che potresti non aspettarti. Quando inserisci più righe contemporaneamente, alle righe potrebbero non essere assegnati ID nell'ordine esatto in cui ti aspetti e potrebbero "apparire" (diventare visibili) in un ordine diverso rispetto all'ordine in cui sono stati assegnati ID e inseriti in. Inoltre, se le transazioni vengono annullate, l'ID generato viene eliminato per sempre, quindi si ottengono lacune nella numerazione. Questo è molto utile se vuoi che il tuo database sia veloce, ma non è l'ideale se vuoi una numerazione senza interruzioni. Se è quello che ti serve, cerca "sequenza gapless postgresql".