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 IDENTITYSpalte machen und (2) sicherstellen, dass sie IDENTITYbeginnt 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 IDENTITYSpalte, die bei 21 für den nächsten Datensatz beginnt, der eingefügt wird. In diesem Beispiel xyzreprä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_tempund setzen diese Spalte auf die idWerte 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 idSpalte löschen (Sie können IDENTITYeiner 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 IDENTITYzusammen 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_INSERTfür die Tabelle aktivieren. Dies bedeutet, dass Sie die Werte einer IDENTITYSpalte 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 DELETEalle Zeilen in der Tabelle, aber die Zeilen, die Sie löschen, OUTPUTdirekt in derselben Tabelle - jedoch mit bestimmten Werten für die idSpalte (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_INSERTwieder 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 IDENTITYSpalte neu auslegen , damit die nächsten Datensätze idnach der höchsten vorhandenen Nummer in der idSpalte 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 idZahl 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 TRANSACTIONes 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 .. INTOfunktioniert 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 idSpalte 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 INSERTund DELETElö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
idSpalte als IDENTITY,
- Gedeck
IDENTITY_INSERT ONfür den Tisch,
- Füllen Sie die Tabelle,
- Set
IDENTITY_INSERT OFFund
- Erneuere die Identität.
IDENTITY?