152

Ho un database MS SQL 2005 con una tabella Test con la colonna ID. ID è una colonna Identity.Come modificare i valori della colonna Identity a livello di codice?

Ho righe in questa tabella e tutte hanno il corrispondente valore autoincrementato ID.

Ora vorrei cambiare ogni ID in questa tabella come questa:

ID = ID + 1 

Ma quando faccio questo ottengo un errore:

Cannot update identity column 'ID'. 

Ho provato questo:

ALTER TABLE Test NOCHECK CONSTRAINT ALL 
set identity_insert ID ON 

Ma questo non risolve il problema.

Ho bisogno di avere l'identità impostata su questa colonna, ma ho bisogno di cambiare anche i valori di volta in volta. Quindi la mia domanda è come realizzare questo compito.

risposta

212

È necessario

set identity_insert YourTable ON 

Quindi eliminare la riga e reinserirla con diversa identità.

volta che avete fatto l'inserto non dimenticate di accendere IDENTITY_INSERT off

set identity_insert YourTable OFF 
+130

impostando questo funzionerà solo quando si inseriscono dati e non quando si aggiorna. L'istruzione UPDATE continuerà a fallire. –

+29

Per un aggiornamento, è necessario eliminare e reinserire. Non c'è altro modo. – ashes999

+1

@ MartinSmith la tua soluzione sembra troppo lunga.Essere in grado di farlo in due fasi (identity-off, delete/insert, identity-on) è molto più efficace. – ashes999

26

Tramite l'interfaccia utente in Gestione SQL Server 2005, modificare la colonna rimuovere la proprietà autonumber (identity) della colonna (selezionare la tabella facendo clic con il pulsante destro del mouse su di essa e selezionare "Progettazione").

Quindi eseguire la query:

UPDATE table SET Id = Id + 1 

Poi vai e aggiungere la proprietà autonumber torna alla colonna.

+4

e come fare questo da codice? –

+3

Se si apporta la modifica manualmente, è possibile chiedere al gestore di generare lo script SQL per la modifica (menu di progettazione tabella, generare script di modifica). Per questa modifica crea una nuova tabella e copia i dati, quindi elimina l'originale. –

+2

@tomaszs - Un esempio di codice che è anche più efficiente in quanto non ricostruisce fisicamente la tabella (lo farebbe due volte) è nella mia risposta in ritardo [qui] (http://stackoverflow.com/a/17249583/ 73226) –

4

Se la colonna non è un PK, è sempre possibile creare una nuova colonna nella tabella con i numeri incrementati, rilasciare l'originale e quindi modificare quello nuovo in modo che sia il vecchio.

curioso di sapere il motivo per cui potrebbe essere necessario fare questo ... la maggior parte che abbia mai avuto a futz con colonne identità era per riempire i numeri e ho appena finito per usare DBCC CHECKIDENT (tablename, RESEED, newnextnumber)

buona fortuna!

1

La modifica dell'identità può non riuscire a seconda di un numero di fattori, principalmente ruotando attorno agli oggetti/alle relazioni collegate alla colonna id. Sembra che il design di db sia un problema qui dato che gli id ​​dovrebbero essere cambiati raramente se non mai (sono sicuro che hai le tue ragioni e stai cacciando le modifiche). Se hai davvero bisogno di cambiare id di volta in volta, ti suggerirei di creare una nuova colonna id fittizia che non sia la chiave primaria/autonumber che puoi gestire tu stesso e generare dai valori correnti. In alternativa, l'idea di Chrisotphers di cui sopra sarebbe il mio altro suggerimento se hai problemi con l'inserimento di identità.

Buona fortuna

PS non è mancato perché l'ordine sequenziale è in esecuzione in cerca di aggiornare un valore nell'elenco a un elemento che esiste già nella lista di ID? aggrappandosi a cannucce, magari aggiungendo il numero di righe + 1, se poi funziona sottrarre il numero di righe: -S

18

Innanzitutto l'impostazione di IDENTITY_INSERT on o off per quella materia non funzionerà per ciò che si richiede (è utilizzato per l'inserimento di nuovi valori, ad esempio per colmare le lacune).

Fare l'operazione tramite la GUI crea solo una tabella temporanea, copia tutti i dati in una nuova tabella senza un campo identità e rinomina la tabella.

1

Se è necessario modificare occasionalmente gli ID, è preferibile non utilizzare una colonna Identity. In passato abbiamo implementato manualmente i campi autonumber usando una tabella 'Contatori' che tiene traccia dell'ID successivo per ogni tabella. IIRC lo abbiamo fatto perché le colonne Identity stavano causando il danneggiamento del database in SQL2000 ma essere in grado di cambiare ID era occasionalmente utile per i test.

6

DBCC CHECKIDENT ('databasename.dbo.orders', RESEED, 999) è possibile modificare un numero qualsiasi colonna di identità con questo comando, e anche tu puoi iniziare quel numero di campo da ogni numero desiderato.per esempio nel mio comando chiedo di iniziare da 1000 (999 + 1) sperare che sia sufficiente ... buona fortuna

9

Questo può essere fatto usando una tabella temporanea.

L'idea

  • vincoli disabilitare (nel caso in cui il vostro id fa riferimento una chiave esterna)
  • creare una tabella temporanea con il nuovo id
  • cancellare il contenuto della tabella
  • copiare indietro i dati dalla tabella copiata alla tabella originale
  • abilita i vincoli disabilitati in precedenza

query SQL

Diciamo che il vostro tavolo test hanno due colonne aggiuntive (column2 e column3) e che ci sono 2 tavoli con le chiavi esterne riferimento test chiamato foreign_table1 e foreign_table2 (perché i problemi della vita reale non sono mai semplici).

alter table test nocheck constraint all; 
alter table foreign_table1 nocheck constraint all; 
alter table foreign_table2 nocheck constraint all; 
set identity_insert test on; 

select id + 1 as id, column2, column3 into test_copy from test v; 
delete from test; 
insert into test(id, column2, column3) 
select id, column2, column3 from test_copy 

alter table test check constraint all; 
alter table foreign_table1 check constraint all; 
alter table foreign_table2 check constraint all; 
set identity_insert test off; 
drop table test_copy; 

Questo è tutto.

0

Ho visto un buon articolo che mi ha aiutato all'ultimo momento. Stavo cercando di inserire poche righe in una tabella che aveva una colonna Identity ma l'ho fatta in modo errato e devo cancellare di nuovo. Una volta cancellate le righe, la mia colonna Identity è stata cambiata. Stavo cercando di trovare un modo per aggiornare la colonna che era stata inserita, ma senza fortuna. Così, durante la ricerca su Google ha trovato un link ..

  1. eliminato il colonne che è stata inserita in modo errato
  2. Usa inserto forza utilizzando l'identità on/off (illustrate di seguito)

http://beyondrelational.com/modules/2/blogs/28/posts/10337/sql-server-how-do-i-insert-an-explicit-value-into-an-identity-column-how-do-i-update-the-value-of-an.aspx

+0

Non sei sicuro di aver davvero risposto alla domanda qui, però. –

39

I valori delle colonne IDENTITY sono immutabili.

Tuttavia è possibile cambiare i metadati della tabella per rimuovere la proprietà IDENTITY, effettuare l'aggiornamento, quindi tornare indietro.

Assumendo la seguente struttura

CREATE TABLE Test 
(
ID INT IDENTITY(1,1) PRIMARY KEY, 
X VARCHAR(10) 
) 

INSERT INTO Test 
OUTPUT INSERTED.* 
SELECT 'Foo' UNION ALL 
SELECT 'Bar' UNION ALL 
SELECT 'Baz' 

Poi si può fare

/*Define table with same structure but no IDENTITY*/ 
CREATE TABLE Temp 
(
ID INT PRIMARY KEY, 
X VARCHAR(10) 
) 

/*Switch table metadata to new structure*/ 
ALTER TABLE Test SWITCH TO Temp; 

/*Do the update*/ 
UPDATE Temp SET ID = ID + 1; 

/*Switch table metadata back*/ 
ALTER TABLE Temp SWITCH TO Test; 

/*ID values have been updated*/ 
SELECT * 
FROM Test 

/*Safety check in case error in preceding step*/ 
IF NOT EXISTS(SELECT * FROM Temp) 
    DROP TABLE Temp /*Drop obsolete table*/ 

In SQL Server 2012 è possibile avere un incremento colonna di auto che può anche essere aggiornato più semplicemente con SEQUENCES

CREATE SEQUENCE Seq 
    AS INT 
    START WITH 1 
    INCREMENT BY 1 

CREATE TABLE Test2 
(
ID INT DEFAULT NEXT VALUE FOR Seq NOT NULL PRIMARY KEY, 
X VARCHAR(10) 
) 

INSERT INTO Test2(X) 
SELECT 'Foo' UNION ALL 
SELECT 'Bar' UNION ALL 
SELECT 'Baz' 

UPDATE Test2 SET ID+=1 
+0

+1 per la risposta chiara e le informazioni sulle sequenze in SQL Server 2012. –

+1

Molto lucido. Impara qualcosa di nuovo ogni giorno (ho provato questo su SQLExpress, nonostante SWITCH TO non utilizzi il partizionamento, apparentemente). Si noti che la tabella deve corrispondere esattamente a molto (indici, FK, ecc.) –

+0

Il metodo switch funziona quando PK, FK, Index e Views sono creati sulla tabella originale? Si romperanno usando questo metodo? –

1

È possibile inserire nuove righe con mod valori ified e quindi eliminare le vecchie righe. Seguendo l'esempio cambiare ID per essere uguale a stranieri chiave PersonID

SET IDENTITY_INSERT [PersonApiLogin] ON 

INSERT INTO [PersonApiLogin](
     [Id] 
     ,[PersonId] 
     ,[ApiId] 
     ,[Hash] 
     ,[Password] 
     ,[SoftwareKey] 
     ,[LoggedIn] 
     ,[LastAccess]) 
SELECT [PersonId] 
     ,[PersonId] 
     ,[ApiId] 
     ,[Hash] 
     ,[Password] 
     ,[SoftwareKey] 
     ,[LoggedIn] 
     ,[LastAccess] 
FROM [db304].[dbo].[PersonApiLogin] 
GO 

DELETE FROM [PersonApiLogin] 
WHERE [PersonId] <> ID 
GO 
SET IDENTITY_INSERT [PersonApiLogin] OFF 
GO 
0

Molto bella domanda, prima dobbiamo sul l'IDENTITY_INSERT per la tabella specifica, dopo che eseguire la query di inserimento (occorre specificare il nome della colonna).

Nota: Dopo modificare la colonna l'identità, non dimenticate di fuori l'IDENTITY_INSERT. Se non hai fatto, non puoi modificare la colonna Identity per qualsiasi altra tabella.

SET IDENTITY_INSERT Emp_tb_gb_Menu ON 
    INSERT Emp_tb_gb_Menu(MenuID) VALUES (68) 
SET IDENTITY_INSERT Emp_tb_gb_Menu OFF 

http://allinworld99.blogspot.com/2016/07/how-to-edit-identity-field-in-sql.html

1

Prima salvare tutti gli ID e li altera programmazione ai valori wan't, quindi rimuoverli dal database e quindi inserire di nuovo con qualcosa di simile:

use [Name.Database] 
go 
set identity_insert [Test] ON 
insert into [dbo].[Test] 
      ([Id]) 
    VALUES 
      (2) 
set identity_insert [Test] OFF 

Per utilizzo di inserti di massa:

use [Name.Database] 
go 
set identity_insert [Test] ON 
BULK INSERT [Test] 
FROM 'C:\Users\Oscar\file.csv' 
WITH (FIELDTERMINATOR = ';', 
     ROWTERMINATOR = '\n', 
     KEEPIDENTITY) 
set identity_insert [Test] OFF 

Dati di esempio da file.csv:

2; 
3; 
4; 
5; 
6; 

Se non si imposta identity_insert off si otterrà il seguente errore:

Cannot insert explicit value for identity column in table 'Test' when IDENTITY_INSERT is set to OFF.

Problemi correlati