Autoincremento PostgreSQL


579

Sto passando da MySQL a PostgreSQL e mi chiedevo come posso fare i valori di autoincremento. Ho visto nei documenti PostgreSQL un tipo di dati "seriale", ma ottengo errori di sintassi quando lo uso (in v8.0).


9
se fornissi la query e l'errore che stai riscontrando, forse qualcuno potrebbe dirti cosa non va nella query.

2
Il mio primo successo è anche Mich 'e dato che è una domanda che ha abbastanza punti di vista per essere pertinente, perché non votarlo. PS non è banale se non sai come farlo.
baash05,

1
SERIAL è la scelta preferita se il driver client è Npgsql. Il provider sta selezionando internamente nuovi valori dopo un INSERT usando SELECT currval (pg_get_serial_sequence ('table', 'column')). Ciò fallirà se la colonna sottostante non è di tipo seriale (tipo numerico + sequenza esplicita per esempio)
Olivier MATROT

Solo per curiosità ... Perché qualcuno deve migrare da MySQL che è molto buono, a PostgreSql?
villamejia

17
... che è ancora meglio.
Rohmer,

Risposte:


702

Sì, SERIAL è la funzione equivalente.

CREATE TABLE foo (
id SERIAL,
bar varchar);

INSERT INTO foo (bar) values ('blah');
INSERT INTO foo (bar) values ('blah');

SELECT * FROM foo;

1,blah
2,blah

SERIAL è solo una macro di creazione tabella attorno alle sequenze. Non è possibile modificare SERIAL su una colonna esistente.


19
citare il nome della tabella è una brutta pratica
Evan Carroll,

71
Citando i nomi delle tabelle è un'abitudine poiché ho ereditato un DB che aveva nomi di casi misti e citando i nomi delle tabelle è un requisito d'uso.
Trey,

26
@Evan Carroll - Perché è una cattiva abitudine (solo chiedendo)?
Christian,

27
perché a meno che tu non abbia un tavolo "Table"e "table"poi lo lasci non quotato e lo canonicalizzi a table. La convenzione semplicemente non usa mai le virgolette in Pg. Se vuoi, puoi usare nomi di casi misti per l'aspetto, ma non richiederlo: CREATE TABLE fooBar ( .. ); SELECT * FROM fooBar;funzionerà, come funzionerà SELECT * FROM foobar.
Evan Carroll,

26
Per documento postgres, citare costantemente o non quotare: postgresql.org/docs/current/interactive/…
Καrτhικ

225

È possibile utilizzare qualsiasi altro tipo di dati intero , ad esempio smallint.

Esempio :

CREATE SEQUENCE user_id_seq;
CREATE TABLE user (
    user_id smallint NOT NULL DEFAULT nextval('user_id_seq')
);
ALTER SEQUENCE user_id_seq OWNED BY user.user_id;

Meglio usare il proprio tipo di dati, piuttosto che il tipo di dati seriale dell'utente .


11
Direi che questa è in realtà la risposta migliore perché mi ha permesso di modificare una tabella che avevo appena creato in PostgreSQL impostando le colonne come predefinite (dopo aver letto su CREATE SEQUENCE postgresql.org/docs/8.1/interactive/sql-createsequence.html ) . TUTTAVIA, non sono del tutto sicuro del perché tu abbia cambiato proprietario.
JayC,

12
@JayC: Dalla documentazione : Infine, la sequenza è contrassegnata come "di proprietà di" la colonna, in modo che verrà eliminata se la colonna o la tabella viene eliminata.
user272735,

9
perché la community di postgres non reinventa la parola chiave autoincremento?
Dott. Deo,

2
@Dr Deo: usano invece la parola chiave autoincrement seriale, non so perché :)
Ahmad

4
C'è anche un piccolo messaggio se vuoi solo un tipo di dati più piccolo.
beldaz,

110

Se vuoi aggiungere una sequenza all'id nella tabella che già esiste puoi usare:

CREATE SEQUENCE user_id_seq;
ALTER TABLE user ALTER user_id SET DEFAULT NEXTVAL('user_id_seq');

Cos'è la sequenza? Dov'è AUTO_INCREMENT?
Verde,

23
@Verde: AUTO_INCREMENT non fa parte dello standard SQL, è specifico per MySQL. Le sequenze sono qualcosa che fa un lavoro simile in PostgreSQL.
beldaz,

5
se usi 'id SERIAL', creerà automaticamente una sequenza in PostgreSQL. Il nome di quella sequenza sarà <nome tabella> _ <nome colonna> _seq
Jude Niroshan

Non devi usare ALTER COLUMN user_id?
Alec,

Ho provato questo metodo ma ricevo un errore: ERROR: syntax error at or near "DEFAULT"qualche suggerimento?
Ely Fialkoff,

44

Mentre sembra che le sequenze siano l' equivalente di Auto_increment di MySQL, ci sono alcune differenze sottili ma importanti:

1. Incremento delle query non riuscite Sequenza / Seriale

La colonna seriale viene incrementata in caso di query non riuscite. Ciò porta alla frammentazione da query non riuscite, non solo alle eliminazioni di riga. Ad esempio, esegui le seguenti query sul tuo database PostgreSQL:

CREATE TABLE table1 (
  uid serial NOT NULL PRIMARY KEY,
  col_b integer NOT NULL,
  CHECK (col_b>=0)
);

INSERT INTO table1 (col_b) VALUES(1);
INSERT INTO table1 (col_b) VALUES(-1);
INSERT INTO table1 (col_b) VALUES(2);

SELECT * FROM table1;

Dovresti ottenere il seguente output:

 uid | col_b 
-----+-------
   1 |     1
   3 |     2
(2 rows)

Nota come si passa da 1 a 3 anziché da 1 a 2.

Ciò si verifica ancora se si dovesse creare manualmente la propria sequenza con:

CREATE SEQUENCE table1_seq;
CREATE TABLE table1 (
    col_a smallint NOT NULL DEFAULT nextval('table1_seq'),
    col_b integer NOT NULL,
    CHECK (col_b>=0)
);
ALTER SEQUENCE table1_seq OWNED BY table1.col_a;

Se si desidera verificare la differenza tra MySQL, eseguire quanto segue su un database MySQL:

CREATE TABLE table1 (
  uid int unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
  col_b int unsigned NOT NULL
);

INSERT INTO table1 (col_b) VALUES(1);
INSERT INTO table1 (col_b) VALUES(-1);
INSERT INTO table1 (col_b) VALUES(2);

Si dovrebbe ottenere quanto segue senza frustrazione :

+-----+-------+
| uid | col_b |
+-----+-------+
|   1 |     1 |
|   2 |     2 |
+-----+-------+
2 rows in set (0.00 sec)

2. L'impostazione manuale del valore della colonna seriale può causare il fallimento di query future.

Questo è stato sottolineato da @trev in una risposta precedente.

Per simularlo, imposta l'UID su 4 che "si scontrerà" in seguito.

INSERT INTO table1 (uid, col_b) VALUES(5, 5);

Dati della tabella:

 uid | col_b 
-----+-------
   1 |     1
   3 |     2
   5 |     5
(3 rows)

Esegui un altro inserto:

INSERT INTO table1 (col_b) VALUES(6);

Dati della tabella:

 uid | col_b 
-----+-------
   1 |     1
   3 |     2
   5 |     5
   4 |     6

Ora se esegui un altro inserto:

INSERT INTO table1 (col_b) VALUES(7);

Non funzionerà con il seguente messaggio di errore:

ERRORE: il valore chiave duplicato viola il vincolo univoco "table1_pkey" DETTAGLIO: Key (uid) = (5) esiste già.

Al contrario, MySQL gestirà questo con garbo come mostrato di seguito:

INSERT INTO table1 (uid, col_b) VALUES(4, 4);

Ora inserisci un'altra riga senza impostare uid

INSERT INTO table1 (col_b) VALUES(3);

La query non ha esito negativo, passa a 5:

+-----+-------+
| uid | col_b |
+-----+-------+
|   1 |     1 |
|   2 |     2 |
|   4 |     4 |
|   5 |     3 |
+-----+-------+

Il test è stato eseguito su MySQL 5.6.33, per Linux (x86_64) e PostgreSQL 9.4.9


10
Stai dando un confronto, ma non vedo alcuna soluzione qui! È una risposta?
Anwar,

4
@Anwar semplicemente estende le varie risposte che affermano che la risposta deve usare un seriale / sequenza. Ciò fornisce alcuni contesti importanti da prendere in considerazione.
Programster,

39

A partire da Postgres 10, sono supportate anche le colonne di identità definite dallo standard SQL:

create table foo 
(
  id integer generated always as identity
);

crea una colonna di identità che non può essere ignorata se non esplicitamente richiesto. Il seguente inserimento fallirà con una colonna definita come generated always:

insert into foo (id) 
values (1);

Questo può tuttavia essere annullato:

insert into foo (id) overriding system value 
values (1);

Quando si utilizza l'opzione, generated by defaultsi tratta essenzialmente dello stesso comportamento dell'implementazione esistente serial:

create table foo 
(
  id integer generated by default as identity
);

Quando un valore viene fornito manualmente, anche la sequenza sottostante deve essere regolata manualmente, lo stesso di una serialcolonna.


Una colonna identità non è una chiave primaria per impostazione predefinita (proprio come una serialcolonna). Se dovrebbe essere uno, un vincolo chiave primaria deve essere definito manualmente.


26

Spiacenti, per riproporre una vecchia domanda, ma questa è stata la prima domanda / risposta Stack Overflow che è emersa su Google.

Questo post (che è arrivato per primo su Google) parla dell'utilizzo della sintassi più aggiornata per PostgreSQL 10: https://blog.2ndquadrant.com/postgresql-10-identity-columns/

che sembra essere:

CREATE TABLE test_new (
    id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
);

Spero che aiuti :)


1
Questo è davvero il modo di procedere in PostgreSQL 10 ed è la stessa sintassi di altri software di database come DB2 o Oracle.
adriaan,

1
@adriaan In realtà i GENERATED … AS IDENTITYcomandi sono SQL standard. Aggiunto per la prima volta in SQL: 2003 , quindi chiarito in SQL: 2008 . Vedi le funzioni # T174 e F386 e T178.
Basil Bourque,

16

Devi fare attenzione a non inserire direttamente nel tuo SERIAL o campo sequenza, altrimenti la tua scrittura fallirà quando la sequenza raggiunge il valore inserito:

-- Table: "test"

-- DROP TABLE test;

CREATE TABLE test
(
  "ID" SERIAL,
  "Rank" integer NOT NULL,
  "GermanHeadword" "text" [] NOT NULL,
  "PartOfSpeech" "text" NOT NULL,
  "ExampleSentence" "text" NOT NULL,
  "EnglishGloss" "text"[] NOT NULL,
  CONSTRAINT "PKey" PRIMARY KEY ("ID", "Rank")
)
WITH (
  OIDS=FALSE
);
-- ALTER TABLE test OWNER TO postgres;
 INSERT INTO test("Rank", "GermanHeadword", "PartOfSpeech", "ExampleSentence", "EnglishGloss")
           VALUES (1, '{"der", "die", "das", "den", "dem", "des"}', 'art', 'Der Mann küsst die Frau und das Kind schaut zu', '{"the", "of the" }');


 INSERT INTO test("ID", "Rank", "GermanHeadword", "PartOfSpeech", "ExampleSentence", "EnglishGloss")
           VALUES (2, 1, '{"der", "die", "das"}', 'pron', 'Das ist mein Fahrrad', '{"that", "those"}');

 INSERT INTO test("Rank", "GermanHeadword", "PartOfSpeech", "ExampleSentence", "EnglishGloss")
           VALUES (1, '{"der", "die", "das"}', 'pron', 'Die Frau, die nebenen wohnt, heißt Renate', '{"that", "who"}');

SELECT * from test; 

15

Nel contesto della domanda posta e in risposta al commento di @ sereja1c, la creazione SERIALimplicitamente crea sequenze, quindi per l'esempio sopra-

CREATE TABLE foo (id SERIAL,bar varchar);

CREATE TABLEcreerebbe implicitamente una sequenza foo_id_seqper la colonna seriale foo.id. Pertanto, SERIAL[4 byte] è utile per la sua facilità d'uso a meno che non sia necessario un tipo di dati specifico per il proprio ID.


3

In questo modo funzionerà sicuramente, spero che aiuti:

CREATE TABLE fruits(
   id SERIAL PRIMARY KEY,
   name VARCHAR NOT NULL
);

INSERT INTO fruits(id,name) VALUES(DEFAULT,'apple');

or

INSERT INTO fruits VALUES(DEFAULT,'apple');

Puoi controllare questo i dettagli nel prossimo link: http://www.postgresqltutorial.com/postgresql-serial/


3

Da PostgreSQL 10

CREATE TABLE test_new (
    id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    payload text
);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.