Det afgørende at forstå er, at SQL-tabeller ikke har en rækkefølge . Rækkefølgen af rækker, du ser, når du SELECT
uden en ORDER BY
forbliver kun den samme, fordi det er hurtigere for databasen at få dem i den rækkefølge end en anden rækkefølge. PostgreSQL returnerer kun rækker i denne rækkefølge, når du laver en sekventiel scanning på bordet; hvis den kan bruge et indeks til forespørgslen, vil du generelt få rækkerne i en anden rækkefølge.
Du vil måske finde dette svar, jeg skrev tidligere, informativt.
I PostgreSQL, UPDATE
s til rækker kan flytte dem til en anden placering i tabellen, og ændre den rækkefølge, de returneres i. Det samme kan autovakuumprocessen i baggrunden og forskellige andre operationer som VACUUM
og CLUSTER
.
Så du må aldrig stole på "standard"-bestillingen til hvad som helst. Hvis du vil give rækker en form for rækkefølge, skal de har en nøgle, som du kan sortere dem på.
Hvis du har oprettet en tabel uden en nøgle og nu indser, at den burde have en, kan du muligvis komme dig fra situationen ved at bruge ctid
system kolonne. Gør ikke stole på dette til produktionsbrug, det er en systemintern kolonne, der kun er synlig for brugere til nødgendannelse og diagnostiske formål. Først skal du se, om den fysiske bestilling på disken faktisk er den rækkefølge, du ønsker:
SELECT row_number() OVER () AS mytable_id, *
FROM mytable
ORDER BY ctid;
Hvis det er det, kan du tilføje en ny nøglekolonne, der er forudindstillet til en auto-inkrementeret nøgle, der anvendes i rækkefølgen på disken. Der er to måder at gøre dette på. Det sikreste er:
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;
så når du er sikker på, at du er tilfreds med resultaterne, DROP TABLE mytable_old;
. Se denne demo:http://sqlfiddle.com/#!12/2cb99/2
En hurtig og nem, men mindre sikker måde er blot at oprette kolonnen og stole på, at PostgreSQL omskriver tabellen fra start til slut:
ALTER TABLE mytable ADD COLUMN mytable_id SERIAL PRIMARY KEY;
Der er absolut ingen garanti at PostgreSQL vil tildele ID'erne i rækkefølge, selvom det i praksis vil gøre det. Se denne SQLFiddle-demo.
Vær opmærksom på, at når du bruger en SEQUENCE
(hvilket er hvad en SERIAL
kolonne opretter), er der nogle få adfærd, du måske ikke forventer. Når du indsætter flere rækker på én gang, får rækkerne muligvis ikke nødvendigvis tildelt id'er i den nøjagtige rækkefølge, du forventer, at de skal, og de kan "vises" (blive synlige) i en anden rækkefølge end den rækkefølge, de blev tildelt id'er og indsat. Hvis transaktioner ruller tilbage, bliver det genererede ID smidt væk for altid, så du får huller i nummereringen. Dette er meget godt, hvis du ønsker, at din database skal være hurtig, men det er ikke ideelt, hvis du vil have nummerering uden mellemrum. Hvis det er det du har brug for, søg efter "postgresql gapless sequence".