Come modificare i valori della colonna identità in modo programmatico?


160

Ho un database MS SQL 2005 con una tabella Testcon colonna ID. IDè una colonna di identità.

Ho righe in questa tabella e tutte hanno il loro valore ID incrementato automaticamente corrispondente.

Ora vorrei cambiare ogni ID in questa tabella in questo modo:

ID = ID + 1

Ma quando lo faccio ricevo un errore:

Impossibile aggiornare la colonna di identità "ID".

Ho provato questo:

    ALTER TABLE Test NOCHECK CONSTRAINT ALL 
    set identity_insert ID ON

Ma questo non risolve il problema.

Devo avere un'identità impostata su questa colonna, ma devo cambiare anche i valori di volta in volta. Quindi la mia domanda è come eseguire questo compito.

Risposte:


220

Devi

set identity_insert YourTable ON

Quindi eliminare la riga e reinserirla con identità diversa.

Una volta terminato l'inserimento, non dimenticare di disattivare identity_insert

set identity_insert YourTable OFF

133
l'impostazione funzionerà solo durante l'inserimento dei dati e non durante l'aggiornamento. L'istruzione UPDATE non riuscirà comunque.
Husein Roncevic,

31
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 passaggi (disattivazione identità, eliminazione / inserimento, attivazione identità) è molto più efficace.
ashes999,

3
@ ashes999 Sono 4 passaggi non 2. La mia risposta è solo uno (crea tabella, passa, aggiorna, passa indietro, rilascia) È presumibile che tu abbia più familiarità con questi passaggi in modo che appaiano meno contorti. L'aggiornamento può essere molto più efficiente quindi eliminare insert quando sono coinvolte molte righe. Inoltre dove tieni le righe eliminate? Se una #temptabella che lasci cadere è un altro passo che non hai contato qui.
Martin Smith,

40

IDENTITY i valori di colonna sono immutabili.

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

Supponendo 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'

Quindi puoi farlo

/*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 una colonna a incremento automatico che può anche essere aggiornata in modo più semplice 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

1
Molto lucido. Impara qualcosa di nuovo ogni giorno (BTW l'ho testato su SQLExpress; nonostante SWITCH TO non utilizzi il partizionamento, a quanto pare). Nota che la tabella deve corrispondere praticamente esattamente (indici, FK, ecc.)
Mark Sowul,

1
Il metodo switch funziona quando hai PK, FK, Index e Views costruiti sulla tabella originale? Si romperanno usando questo metodo?
tj

1
@tj durante la creazione dello script della tabella temporanea dalla tabella di origine, inclusi tutti gli indici e i vincoli. Quindi modificare i nomi della tabella e i vincoli per evitare collisioni. Le viste non causeranno problemi se non indicizzate o schemabound.
Martin Smith,

Non funziona se nella tabella è presente un indice di ricerca full-text. Suppongo che sia possibile rimuoverlo e ricrearlo in seguito, ma non ho ancora testato.
Il

26

Tramite l'interfaccia utente in SQL Server 2005 manager, modifica la colonna rimuovi la proprietà autonumber (identità) della colonna (seleziona la tabella facendo clic destro su di essa e scegli "Design").

Quindi eseguire la query:

UPDATE table SET Id = Id + 1

Quindi vai e aggiungi la proprietà autonumber alla colonna.


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

2
@tomaszs - Un esempio di codice che è anche più efficiente in quanto non ricostruisce fisicamente la tabella (lo farebbe due volte) è nella mia risposta tardiva qui
Martin Smith,

Non è possibile aggiungere nuovamente l'identità. Fai? stackoverflow.com/questions/1049210/…
Tomas Kubes il

Grazie. Questo è stato perfetto Avevo una riga nella mia tabella di cui non ero a conoscenza, quindi i miei script bootstrap per la mia tabella avevano Idvalori di Identità automatica disattivati ​​di 1.
Shiva

18

Innanzitutto l'impostazione di IDENTITY_INSERT attivata o disattivata per quella materia non funzionerà per quello che ti serve (è usata per inserire nuovi valori, come colmare le lacune).

L'esecuzione dell'operazione tramite la GUI crea semplicemente una tabella temporanea, copia tutti i dati su una nuova tabella senza un campo identità e rinomina la tabella.


9

Questo può essere fatto usando una tabella temporanea.

L'idea

  • disabilita i vincoli (nel caso in cui il tuo ID sia referenziato da una chiave esterna)
  • creare una tabella temporanea con il nuovo ID
  • elimina il contenuto della tabella
  • copia i dati dalla tabella copiata alla tabella originale
  • abilitare vincoli precedentemente disabilitati

Query SQL

Supponiamo che la tua testtabella abbia due colonne aggiuntive ( column2e column3) e che ci siano 2 tabelle con riferimenti a chiavi esterne testchiamate foreign_table1e foreign_table2(poiché 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.


6

DBCC CHECKIDENT ('databasename.dbo.orders', RESEED, 999) è possibile modificare qualsiasi numero di colonna di identità con questo comando e inoltre è possibile avviare quel numero di campo da ogni numero desiderato. Ad esempio nel mio comando chiedo di iniziare da 1000 (999 + 1) sperano che basti ... buona fortuna


4

Se la colonna non è un PK, puoi sempre creare una NUOVA colonna nella tabella con i numeri incrementati, eliminare l'originale e quindi modificare quella nuova in modo che sia vecchia.

curioso di sapere perché potresti aver bisogno di farlo ... la maggior parte che abbia mai avuto a che fare con le colonne Identity era di riempire i numeri e ho appena finito di usare DBCC CHECKIDENT (tablename, RESEED, newnextnumber)

in bocca al lupo!


1

La modifica dell'identità può non riuscire a seconda di una serie di fattori, principalmente ruotanti attorno agli oggetti / relazioni collegati alla colonna ID. Sembra che il design di db sia un problema qui come gli ID dovrebbero raramente se mai cambiare (sono sicuro che hai i tuoi motivi e stai mettendo in cascata i cambiamenti). Se hai davvero bisogno di cambiare gli ID di tanto in tanto, suggerirei di creare una nuova colonna ID fittizio che non sia la chiave primaria / il numero automatico che puoi gestire tu stesso e generare dai valori correnti. In alternativa, l'idea di Chrisotphers sopra sarebbe il mio altro suggerimento se hai problemi a consentire l'inserimento dell'identità.

In bocca al lupo

PS non sta fallendo perché l'ordine sequenziale in cui è in esecuzione sta provando ad aggiornare un valore nell'elenco a un elemento che esiste già nell'elenco degli ID? stringendo a cannucce, forse aggiungi il numero di righe + 1, quindi se funziona sottrarre il numero di righe: -S


1

Se è necessario modificare gli ID di tanto in tanto, probabilmente è meglio non utilizzare una colonna di identità. In passato abbiamo implementato manualmente i campi di numero automatico utilizzando una tabella "Contatori" che tiene traccia dell'ID successivo per ogni tabella. IIRC lo abbiamo fatto perché le colonne di identità stavano causando la corruzione del database in SQL2000 ma la possibilità di modificare gli ID era occasionalmente utile per i test.


1

È possibile inserire nuove righe con valori modificati e quindi eliminare le vecchie righe. Nell'esempio seguente, cambiare l'ID in modo che sia uguale alla chiave esterna 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

1

Prima salva tutti gli ID e modificali a livello di codice sui valori che non desideri, quindi rimuovili dal database e poi inseriscili di nuovo usando 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 l'uso con inserti sfusi:

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 è identity_insertdisattivati, verrà visualizzato il seguente errore:

Impossibile inserire il valore esplicito per la colonna identità nella tabella "Test" quando IDENTITY_INSERT è impostato su OFF.


0

Ho visto un buon articolo che mi ha aiutato all'ultimo momento .. Stavo cercando di inserire alcune righe in una tabella che aveva una colonna di identità ma l'avevo fatto in modo errato e dovevo eliminarla. Dopo aver eliminato le righe, la mia colonna di identità è stata modificata. Stavo cercando di trovare un modo per aggiornare la colonna che era stata inserita ma - senza fortuna. Quindi, durante la ricerca su google ho trovato un link ..

  1. Eliminate le colonne che sono state inserite erroneamente
  2. Usa l'inserimento forzato usando l'identità on / off (spiegato 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-il-value-of-an.aspx


1
Non sono sicuro di aver davvero risposto alla domanda qui, però.
Andrew Barber,

0

Domanda molto bella, per prima cosa è necessario su IDENTITY_INSERT per la tabella specifica, quindi eseguire la query di inserimento (è necessario specificare il nome della colonna).

Nota: dopo aver modificato la colonna identità, non dimenticare di disattivare IDENTITY_INSERT. In caso contrario, non è possibile modificare la colonna identità 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

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.