Ich verstehe Ihre Frage so, dass Sie eine vorhandene Tabelle mit einer Spalte haben, die bisher mit manuellen Werten gefüllt war, und jetzt möchten Sie (1) diese Spalte zu einer IDENTITY
Spalte machen und (2) sicherstellen, dass sie IDENTITY
beginnt vom neuesten Wert in den vorhandenen Zeilen.
Zunächst einige Testdaten zum Spielen:
CREATE TABLE dbo.ident_test (
id int NOT NULL,
xyz varchar(10) NOT NULL,
CONSTRAINT PK_ident_test PRIMARY KEY CLUSTERED (id)
);
INSERT INTO dbo.ident_test (id, xyz)
VALUES (1, 'test'),
(2, 'test'),
(5, 'test'),
(6, 'test'),
(10, 'test'),
(18, 'test'),
(19, 'test'),
(20, 'test');
Das Ziel ist es, die Primärschlüsselspalte der Tabelle zu erstellen id
, eine IDENTITY
Spalte, die bei 21 für den nächsten Datensatz beginnt, der eingefügt wird. In diesem Beispiel xyz
repräsentiert die Spalte alle anderen Spalten der Tabelle.
Bevor Sie etwas tun, lesen Sie bitte die Warnungen am Ende dieses Beitrags.
Zunächst einmal, falls etwas schief geht:
BEGIN TRANSACTION;
Nun fügen wir eine temporäre Arbeitsspalte hinzu id_temp
und setzen diese Spalte auf die id
Werte der vorhandenen Spalte:
ALTER TABLE dbo.ident_test ADD id_temp int NULL;
UPDATE dbo.ident_test SET id_temp=id;
Als nächstes müssen wir die vorhandene id
Spalte löschen (Sie können IDENTITY
einer vorhandenen Spalte nicht einfach "hinzufügen" , Sie müssen die Spalte als erstellen IDENTITY
). Der Primärschlüssel muss auch gehen, weil die Spalte davon abhängt.
ALTER TABLE dbo.ident_test DROP CONSTRAINT PK_ident_test;
ALTER TABLE dbo.ident_test DROP COLUMN id;
... und fügen Sie die Spalte erneut hinzu, diesmal als IDENTITY
zusammen mit dem Primärschlüssel:
ALTER TABLE dbo.ident_test ADD id int IDENTITY(1, 1) NOT NULL;
ALTER TABLE dbo.ident_test ADD CONSTRAINT PK_ident_test PRIMARY KEY CLUSTERED (id);
Hier wird es interessant. Sie können IDENTITY_INSERT
für die Tabelle aktivieren. Dies bedeutet, dass Sie die Werte einer IDENTITY
Spalte manuell definieren können, wenn Sie neue Zeilen einfügen (jedoch keine vorhandenen Zeilen aktualisieren).
SET IDENTITY_INSERT dbo.ident_test ON;
Mit diesem Satz befinden sich DELETE
alle Zeilen in der Tabelle, aber die Zeilen, die Sie löschen, OUTPUT
direkt in derselben Tabelle - jedoch mit bestimmten Werten für die id
Spalte (aus der Sicherungsspalte).
DELETE FROM dbo.ident_test
OUTPUT deleted.id_temp AS id, deleted.xyz
INTO dbo.ident_test (id, xyz);
Sobald Sie fertig sind, schalten Sie ihn IDENTITY_INSERT
wieder aus.
SET IDENTITY_INSERT dbo.ident_test OFF;
Löschen Sie die temporäre Spalte, die wir hinzugefügt haben:
ALTER TABLE dbo.ident_test DROP COLUMN id_temp;
Und schließlich die IDENTITY
Spalte neu auslegen , damit die nächsten Datensätze id
nach der höchsten vorhandenen Nummer in der id
Spalte fortgesetzt werden :
DECLARE @maxid int;
SELECT @maxid=MAX(id) FROM dbo.ident_test;
DBCC CHECKIDENT ("dbo.ident_test", RESEED, @maxid)
In der Beispieltabelle ist die höchste id
Zahl 20.
SELECT * FROM dbo.ident_test;
Fügen Sie eine weitere Zeile hinzu und überprüfen Sie die neue IDENTITY
:
INSERT INTO dbo.ident_test (xyz) VALUES ('New row');
SELECT * FROM dbo.ident_test;
Im Beispiel wird die neue Zeile haben id=21
. Wenn Sie zufrieden sind, führen Sie die Transaktion aus:
COMMIT TRANSACTION;
Wichtig
Dies ist keine triviale Operation und birgt eine Reihe von Risiken, die Sie berücksichtigen sollten.
Führen Sie dies in einer dedizierten Testumgebung durch. Backups haben. :)
Ich benutze BEGIN/COMMIT TRANSACTION
es gerne, weil es verhindert, dass andere Prozesse mit der Tabelle in Konflikt geraten, während Sie gerade dabei sind, sie zu ändern, und es gibt Ihnen die Möglichkeit, alles zurückzusetzen, wenn etwas schief geht. Jeder andere Prozess, der versucht, auf Ihre Tabelle zuzugreifen, bevor Sie Ihre Transaktion festgeschrieben haben, wird jedoch warten. Dies kann ziemlich schlimm sein, wenn Sie einen großen Tisch haben und / oder sich in einer Produktionsumgebung befinden.
OUTPUT .. INTO
funktioniert nicht, wenn Ihre Zieltabelle Fremdschlüsseleinschränkungen oder eine Reihe anderer Funktionen enthält, an die ich mich nicht mehr ganz genau erinnern kann. Sie können die Daten stattdessen in eine temporäre Tabelle entladen und dann wieder in die Originaltabelle einfügen. Möglicherweise können Sie die Partitionsumschaltung verwenden (auch wenn Sie keine Partitionen verwenden).
Führen Sie diese Anweisungen einzeln aus, nicht als Stapel oder in einer gespeicherten Prozedur.
Denken Sie an andere Dinge, die von der id
Spalte abhängen , die Sie löschen und neu erstellen. Alle Indizes müssen gelöscht und neu erstellt werden (wie wir es mit dem Primärschlüssel getan haben). Denken Sie daran, jeden Index und jede Einschränkung zu skripten, die Sie zuvor neu erstellen müssen.
Deaktivieren Sie alle INSERT
und DELETE
löst auf dem Tisch.
Wenn das Neuerstellen der Tabelle eine Option ist:
Wenn es für Sie eine Option ist, die Tabelle neu zu erstellen, ist alles viel einfacher:
- Erstellen Sie die leere Tabelle mit der
id
Spalte als IDENTITY
,
- Gedeck
IDENTITY_INSERT ON
für den Tisch,
- Füllen Sie die Tabelle,
- Set
IDENTITY_INSERT OFF
und
- Erneuere die Identität.
IDENTITY
?