Domanda

In MS Sql Server è facile creare campi autoincremento. Nei miei sistemi ho smesso di usare i campi autoincremento per chiavi primarie, e ora uso GUID. E 'stato fantastico, ho un sacco di vantaggi con questo cambiamento. Ma in un altro settori chiave non primarie, mi è stato bisogno implementare un "autoincrement soft". È perché il mio sistema è indipendente dal database, in modo da creare il valore AutoInc programmazione in C #.

Vorrei informazioni sulle soluzioni per i campi autoincremento su database senza autoincrement, quale sia la soluzione che l'utilizzo e perché? V'è una certa istruzione SQL ANSI su questo? e generando direttamente dal mio c #, è una soluzione migliore?

PS: so che select max (id) +1 dalla tabella non è davvero concomitante amichevole ...

È stato utile?

Soluzione

Il meccanismo per generare valori ID univoci non deve essere oggetto di isolamento delle transazioni. Questo è necessario per il database per generare un valore distinto per ogni cliente, meglio che il trucco di SELECT MAX(id)+1 FROM table, che si traduce in una condizione di competizione se due client tentano di allocare nuovi valori id contemporaneamente.

Non è possibile simulare questa operazione utilizzando query SQL standard (a meno che non si utilizzano blocchi di tabella o serializzabili transazioni). Deve essere un meccanismo integrato nel motore di database.

ANSI SQL non ha descritto l'operazione di generare valori univoci per chiavi surrogate fino SQL: 2003. Prima di allora, non vi era alcuna norma per le colonne incremento automatico, in modo quasi ogni marca di RDBMS fornito qualche soluzione proprietaria. Naturalmente essi variano molto, e non c'è modo di usarli in modo semplice, indipendente dal database.

  • MySQL ha l'opzione della colonna AUTO_INCREMENT, o SERIAL pseudo-tipo di dati che è equivalente a BIGINT UNSIGNED AUTO_INCREMENT;
  • Microsoft SQL Server ha la possibilità di colonna IDENTITY e NEWSEQUENTIALID() che è qualcosa tra auto-incremento e GUID;
  • Oracle ha un oggetto SEQUENCE;
  • PostgreSQL ha un oggetto SEQUENCE o SERIAL pseudo-tipo di dati che crea implicitamente un oggetto sequenza secondo una convenzione di denominazione;
  • InterBase / Firebird ha un oggetto GENERATOR che è molto simile a un SEQUENCE in Oracle; Firebird 2.1 supporta SEQUENCE troppo;
  • SQLite tratta qualsiasi numero intero dichiarato come chiave primaria come implicitamente incremento automatico;
  • DB2 UDB ha praticamente tutto:. Oggetti SEQUENCE, oppure è possibile dichiarare le colonne con l'opzione "GEN_ID"

Tutti questi meccanismi operano al di fuori di isolamento delle transazioni, assicurando che i clienti simultanei ottengono valori univoci. Inoltre in tutti i casi c'è un modo per interrogare il valore generato più di recente per la sessione corrente . Ci deve essere, in modo da poter usare per inserire righe in una tabella figlio.

Altri suggerimenti

Credo che la tua domanda è in realtà abbastanza buona. Tuttavia, è facile perdersi cercando di trovare una SQL unica soluzione. In realtà si vuole la sicurezza di ottimizzazione e la transazione offerta dalla utilizzando le implementazioni di database dei tipi autoincremento.

Se avete bisogno di astrarre l'implementazione dell'operatore autoincrement, perché non creare una stored procedure per restituire il valore di autoincrement. La maggior parte dei dialetti SQL di accesso memorizzati procedure relativamente allo stesso modo e dovrebbe essere più portabile. Quindi è possibile creare la logica autoincrement specifico database quando si crea lo sProc -. Eliminando la necessità di cambiare molte affermazioni di essere specifico fornitore

Fatto questo modo, i vostri inserti potrebbe essere semplice come:

INSERT INTO foo (id, name, rank, serial_number)
 VALUES (getNextFooId(), 'bar', 'fooRank', 123456);

Poi definire getNextFooId () in un database modo specifico quando il database viene inizializzato.

La maggior parte delle basi di dati che non hanno campi autoincremento come SQL Server (sto pensando di Oracle in particolare) hanno sequenze in cui si chiede la sequenza per il numero successivo. Non importa quante persone stanno chiedendo i numeri allo stesso tempo ognuno ha un numero unico.

La soluzione tradizionale è quella di avere una tabella di ID che sembrano qualcosa di simile

CREATE TABLE ids (
  tablename VARCHAR(32) NOT NULL PRIMARY KEY,
  nextid INTEGER
)

che s popolata con una riga per ogni tabella quando si crea il database.

È poi fare una selezione per ottenere il prossimo ID successivo per la tabella si sta inserendo in, incrementarlo e quindi aggiornare la tabella con il nuovo ID. Ovviamente, ci sono problemi di blocco qui, ma per i database con tassi di inserimento moderati funziona bene. Ed è completamente portatile.

Se avete bisogno di un campo autoincrement non primario-chiave, una bella unica soluzione MySQL per la creazione di sequenze arbitraty è quello di utilizzare la funzione di last_insert_id(expr) relativamente sconosciuto.

  

Se espressione viene dato come argomento a   LAST_INSERT_ID (), il valore della   argomento viene restituito dalla funzione   e viene ricordato come il successivo valore di   essere restituito da LAST_INSERT_ID (). Questo   può essere utilizzato per simulare le sequenze ...

( http: // dev.mysql.com/doc/refman/5.1/en/information-functions.html#function_last-insert-id )

Ecco un esempio che dimostra come una sequenza secondaria può essere mantenuto per la numerazione commenti per ogni post:

CREATE TABLE  `post` (
  `id` INT(10) UNSIGNED NOT NULL,
  `title` VARCHAR(100) NOT NULL,
  `comment_sequence` INT(10) UNSIGNED NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
);

CREATE TABLE  `comment` (
  `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `post_id`  INT(10) UNSIGNED NOT NULL,
  `sequence` INT(10) UNSIGNED NOT NULL,
  `content` TEXT NOT NULL,
  PRIMARY KEY (`id`)
);

INSERT INTO post(id, title) VALUES(1, 'first post');
INSERT INTO post(id, title) VALUES(2, 'second post');

UPDATE post SET comment_sequence=Last_insert_id(comment_sequence+1) WHERE id=1;
INSERT INTO `comment`(post_id, sequence, content) VALUES(1, Last_insert_id(), 'blah');

UPDATE post SET comment_sequence=Last_insert_id(comment_sequence+1) WHERE id=1;
INSERT INTO `comment`(post_id, sequence, content) VALUES(1, Last_insert_id(), 'foo');

UPDATE post SET comment_sequence=Last_insert_id(comment_sequence+1) WHERE id=1;
INSERT INTO `comment`(post_id, sequence, content) VALUES(1, Last_insert_id(), 'bar');

UPDATE post SET comment_sequence=Last_insert_id(comment_sequence+1) WHERE id=2;
INSERT INTO `comment`(post_id, sequence, content) VALUES(2, Last_insert_id(), 'lorem');

UPDATE post SET comment_sequence=Last_insert_id(comment_sequence+1) WHERE id=2;
INSERT INTO `comment`(post_id, sequence, content) VALUES(2, Last_insert_id(), 'ipsum');

SELECT * FROM post;
SELECT * FROM comment;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top