2012-12-21 15 views
9

Voglio inserire le righe in una tabella che ha una chiave primaria univoca, non auto-incrementata.Come inserire una chiave auto_increment nella tabella di SQL Server

C'è una funzione SQL nativo per valutare l'ultima chiave e incrementarlo o devo farlo in due fasi:

key = select max(primary.key) + 1 

INSERT INTO dbo.TABLE (primary.key, field1, fiels2) VALUES (KEY, value1, value2) 
+3

Vuoi dire che hai una colonna [IDENTITY'] (http://msdn.microsoft.com/en-us/library/ms186775.aspx) sul tavolo? In caso affermativo, quale problema preciso stai riscontrando che non viene discusso nella documentazione o nelle [molte domande] (http://stackoverflow.com/search?q=sql+identity) in questo sito sull'utilizzo di essi? In un commento qui sotto hai menzionato un errore ma non hai detto esattamente di cosa si tratta. Idealmente, si prega di mostrare lo script 'CREATE TABLE', l'istruzione' INSERT' e il messaggio di errore risultante. – Pondlife

+0

Questo thread ha risolto tutti i miei mal di testa e il codice si sta ricomponendo. Perché ppl lo ha downvoted? –

risposta

10

A giudicare dai commenti in tutto, si ha una chiave primaria sulla tabella che non è una colonna di identità.

Se la versione di SQL Server è SQL 2012 si dovrebbe guardare in sequenze: http://msdn.microsoft.com/en-us/library/ff878091.aspx

In altre versioni che si sia bisogno di ricreare la tabella utilizzando la proprietà IDENTITY (http://msdn.microsoft.com/en -us/library/aa933196 (v = sql.80) .aspx) per la colonna chiave primaria o utilizzare un approccio a due fasi.

Se si segue l'approccio a due fasi, è necessario assicurarsi che gli inserimenti in esecuzione simultanea non finiscano per utilizzare lo stesso nuovo valore. Il modo più semplice per farlo è questo è combinando la selezione e l'inserto in un unico valore e utilizzando la tabella serializable suggerimento:

CREATE TABLE dbo.Tbl1(id INT PRIMARY KEY, val1 INT, val2 INT) 

INSERT INTO dbo.Tbl1(id, val1, val2) 
VALUES((SELECT ISNULL(MAX(id)+1,0) FROM dbo.Tbl1 WITH(SERIALIZABLE, UPDLOCK)), 42, 47); 

SELECT * FROM dbo.Tbl1; 
+0

GRAZIE !!! Ora c'è una soluzione, non è una funzione, ma posso gestire con una subquery, meglio di una procedura in due fasi. Grazie. –

+0

'SERIALIZABLE' è equivalente a' HOLDLOCK' ed è un buon inizio ma * non è sufficiente *. La tua query può ancora fallire con una concorrenza elevata. Devi aggiungere 'UPDLOCK, TABLOCKX'. Le parti di una query vengono eseguite nel tempo e i blocchi vengono acquisiti nel tempo, quindi 'INSERT' viene dopo 'SELECT'. Due client possono 'SELECT' allo stesso tempo con blocchi di lettura completamente compatibili, quindi il secondo viene bloccato mentre il primo si converte in un' UPDLOCK' per il suo 'INSERT', quindi il secondo ha il vecchio valore una volta che il blocco è al di sopra di. È necessario il 'SELECT' per bloccare ** tutti i lettori **! – ErikE

+1

In definitiva, questo pattern 'SELECT max() + 1' non è la procedura migliore e non può essere raccomandato. Le colonne di identità esistono proprio per questa ragione. Usali. – ErikE

17

Dal momento che è auto-generata, semplicemente non fornire:

INSERT INTO bo.TABLE (field1, fiels2) VALUES (value1, value2) 

Aggiornamento: che funzionerà se la colonna è una colonna IDENTITY.

per fornire valori espliciti a una colonna di identità, devi fare questo:

set identity_insert bo.TABLE on 

INSERT INTO bo.TABLE (primary_key, field1, fiels2) VALUES ((SELECT ISNULL(MAX(id) + 1, 0) FROM bo.Table), value1, value2) 

set identity_insert bo.TABLE off 

ma non c'è alcun motivo valido per farlo in questo modo.

+0

Ho provato, genera un errore di vincolo, devo fornire il valore. –

+1

Si prega di inviare l'errore .... e la definizione della tabella. –

+0

Violazione del vincolo PRIMARY KEY 'pk_bo'. Impossibile inserire la chiave duplicata nell'oggetto "dbo.bo". Il valore della chiave duplicata è (921, 0, 2012). –

3

A mio parere la risposta migliore è quella di fissare il vostro tavolo in modo che la colonna PK è una colonna di identità. (Si prega di vedere i miei commenti sulla risposta di Sebastian Meine sul perché la tua risposta attualmente selezionata non è la migliore.) L'unico modo per trasformare un PK esistente in una colonna di identità è scambiare la tabella. Approssimativamente:

BEGIN TRAN; 
-- Rename all constraints in original table 
EXEC sp_rename 'dbo.YourOriginalTable.PK_ConstraintName', 'PKConstraint_Backup'; 
EXEC sp_rename 'dbo.YourOriginalTable.OtherConstraintName', 'OtherConstraintName_Backup'; 
CREATE TABLE dbo.WorkTable (
    YourPKColumn int identity(1, 1) NOT NULL -- your PK converted to identity 
    CONSTRAINT PK_YourOriginalTableConstraintName PRIMARY KEY CLUSTERED, 
    AllOtherColumns -- all your other columns exactly as in the original table 
); 

SET IDENTITY_INSERT dbo.WorkTable ON; 
INSERT dbo.WorkTable (YourPKColumn, AllOtherColumns) 
SELECT YourPKColumn, AllOtherColumns 
FROM dbo.YourOriginalTable WITH (TABLOCKX, HOLDLOCK); 

SET IDENTITY_INSERT dbo.WorkTable OFF; 

-- Drop all FK constraints from other tables pointing to your table 
ALTER TABLE dbo.TableWithFK_1 
DROP CONSTRAINT FK_TableWithFK_1_YourOriginalTableSomethingID; 

-- Swap out the tables 
EXEC sp_rename 'dbo.YourOriginalTable', 'YourOriginalTableBackup'; 
EXEC sp_rename 'dbo.WorkTable', 'YourOriginalTable'; 

-- If you didn't add them in the WorkTable creation, 
-- add all other removed or needed constraints creation 
ALTER TABLE dbo.YourOriginalTable 
ADD CONSTRAINT OriginalConstraint (OriginalConstraintColumns); 
-- Add back FK constraints from other tables to this one. 
COMMIT TRAN; 

Ora si dispone di una tabella con una colonna di identità con un PK in cluster. Puoi inserirle senza problemi. Niente più problemi di concorrenza e stupido SELECT Max() + 1 spazzatura che è così facile da sbagliare.

+0

+1 ovviamente se si tratta di un sistema attivo si vorrà farlo in una transazione esplicita. Altrimenti c'è il rischio di ottenere alcuni dati in 'YourOriginalTable' dopo l''INSERT', ma prima di ridenominarli. –

+0

Grazie Aaron che è una buona presa. Risolto (credo). – ErikE

+0

Spiacente Non è il mio Db, non posso apportare modifiche, è stato progettato per funzionare con un'applicazione ERP. Basta fare la procedura spiegata nella domanda, grazie comunque. –

0

creare tabella se non esiste Emp ( eid int (10) non nullo auto_increment chiave primaria, nome varchar (45) non nullo, età int (5) predefinito 20, stipendio int (5) ) inserire in valori emp (102, 'Ranjan', 21,450000);

Quindi provare sotto query SQL. Aumenterà automaticamente il numero eid al numero successivo.

inserire valori emp (nome, salario) ('Lisma', 118500);

selezionare * da emp;

Problemi correlati