2013-08-22 5 views
12

Ho una tabella postgres con un ID SERIALE.Postgresql SERIAL funziona in modo diverso?

id (serial) name age 

L'inserimento di solito avviene da un'applicazione Web.

ho inserito manualmente due nuovi record Impostazione dell'ID come max (id) +1 ****

Dopo questi 2 inserto quando gli inserti app web 2 discografiche dà errore di chiave duplicata.

Solo per 2 record. Dopo che tutto funziona bene.

La domanda è: perché il mio inserimento manuale non ha incrementato la serie?

L'incremento automatico e la serie sono diversi?

Cosa mi manca qui? MySQL o qualsiasi altro SQL hanno lo stesso problema?

+1

Serial è PostgreSQL questo intero a quattro byte autoincrementante, NON si devono generare i propri numeri se l'ID è seriale. in MySQL questa è una colonna AUTO_INCREMENT più o meno .. –

risposta

39

Quando si crea una colonna serial or bigserial, PostgreSQL in realtà fa tre cose:

  1. crea una colonna int o bigint.
  2. Crea una sequenza (di proprietà della colonna) per generare valori per la colonna.
  3. Imposta il valore predefinito della colonna su nextval() della sequenza.

quando si inserisce un valore senza specificare la colonna serial (o se si specifica esplicitamente DEFAULT il suo valore), saranno chiamati nextval sulla sequenza a:

  1. ritorno il prossimo valore disponibile per la colonna.
  2. Incrementa il valore della sequenza.

Se si fornisce manualmente un valore non predefinito per la colonna serial poi la sequenza non sarà aggiornato e nextval può restituire valori che la colonna serial utilizza già. Quindi, se fai questo genere di cose, dovrai correggere manualmente la sequenza chiamando lo nextval or setval.

Anche tenere a mente che i record possono essere eliminati in modo lacune nella serial colonne sono da aspettarsi in modo da utilizzare max(id) + 1 non è una buona idea anche se non ci sono stati problemi di concorrenza.

Se stai usando serial o bigserial, la cosa migliore è lasciare che PostgreSQL prendersi cura di assegnare i valori per voi e far finta che sono numeri opache che capita di venire fuori in un certo ordine: non assegnale tu stesso e non assumere nulla su di loro se non l'unicità. Questa regola empirica si applica a tutti i database IMO.


io non sono certo come auto_increment opere di MySQL con tutti i diversi tipi di database ma forse the fine manual sarà di aiuto.

+0

grazie. Penso che non ci sia una sequenza extra in mysql. è solo l'ID di incremento automatico. così max (id) +1 funzionerà in mysql ma non in postgres! – zod

+0

ma dovrebbe avere un incremento seriale sequesnce trigger? qual è il tuo suggerimento? so che non è così. basta chiedere un suggerimento – zod

+2

Il mio suggerimento è nella mia risposta: lasciare i valori 'serial' e' auto_increment' al database. Non scherzare affatto con loro. Se si lascia che il database assegni il valore 'serial', la sequenza verrà aggiornata e tutto andrà bene; se si assegna manualmente un valore, è necessario aggiornare manualmente la sequenza. –

7

Se si desidera inserire un record nella tabella con la colonna serial, basta solo dividerlo dalla query, verrà generato automaticamente.

Oppure si può inserire il suo valore defaul con qualcosa di simile:

insert into your_table(id, val) 
values (default, '123'); 

terza opzione è quella di prendere malually valori dalla sequenza seriale direttamente:

insert into your_table(id, val) 
values (nextval(pg_get_serial_sequence('your_table','id')), '123'); 
+0

grazie ... quindi è diverso da mysql..è vero? la sequenza funziona nello stesso modo in Oracle e SQL Server? – zod

+0

@zod È lo stesso in Oracle, ma non ho expiriens con MS SQL Server. –

+0

ottima risposta sul valore predefinito inserito per il tipo SERIAL quando le colonne non sono specificate. Ho cercato l'equivalente di Postgres dell'inserto "null" per AUTO_INCREMENT in MySQL. Grazie. – Morey

2

ho inserito manualmente due nuovi record impostazione l'id come max (id) + 1 * *

Questo approccio è completamente sbagliato e non funzionerà nel database. Ha funzionato per te finora in MySQL solo per pura fortuna.

Se due connessioni eseguono contemporaneamente questo, otterranno lo stesso ID. Può funzionare in modo affidabile solo se blocchi la tabella da letture contemporanee in modo che solo una connessione possa ricevere un ID alla volta.

È anche terribilmente inefficiente.

Questo è il motivo per cui esistono sequenze, in modo che sia possibile ottenere in modo affidabile ID in presenza di inseritori simultanei.

Basta usare:

INSERT INTO my_table(data1, data2) VALUES ('a','b') RETURNING id; 

o:

INSERT INTO my_table(id, data1, data2) VALUES (DEFAULT, 'a','b') RETURNING id; 

DEFAULT è una speciale segnaposto che raccontano il database per ottenere il valore predefinito per quella colonna dalla definizione della tabella. L'impostazione predefinita è nextval('my_table_id_seq'), quindi verrà inserito il valore della sequenza successiva.

Poiché si stanno facendo domande di base sulle sequenze, si consiglia inoltre di considerare che le sequenze non siano prive di spazio. È normale che le sequenze abbiano "buchi", in cui i valori della tabella vanno 1, 3, 4, 5, 9, 10, ....