Ich habe eine Tabelle in einem DB erstellt, der bereits in einem anderen DB vorhanden ist. Es wurde ursprünglich mit den alten DB-Daten gefüllt. Der PK der Tabelle musste die Werte empfangen, die bereits in diesen Datensätzen vorhanden waren, damit es nicht zu einer automatischen Inkrementierung kommen konnte.
Jetzt brauche ich die neue Tabelle, um ihre PK als Autoincrement zu haben. Aber wie kann ich das tun, wenn die PK bereits vorhanden ist und Daten hat?
IDENTITY
?Antworten:
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 sieIDENTITY
beginnt vom neuesten Wert in den vorhandenen Zeilen.Zunächst einige Testdaten zum Spielen:
Das Ziel ist es, die Primärschlüsselspalte der Tabelle zu erstellen
id
, eineIDENTITY
Spalte, die bei 21 für den nächsten Datensatz beginnt, der eingefügt wird. In diesem Beispielxyz
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:
Nun fügen wir eine temporäre Arbeitsspalte hinzu
id_temp
und setzen diese Spalte auf dieid
Werte der vorhandenen Spalte:Als nächstes müssen wir die vorhandene
id
Spalte löschen (Sie könnenIDENTITY
einer vorhandenen Spalte nicht einfach "hinzufügen" , Sie müssen die Spalte als erstellenIDENTITY
). Der Primärschlüssel muss auch gehen, weil die Spalte davon abhängt.... und fügen Sie die Spalte erneut hinzu, diesmal als
IDENTITY
zusammen mit dem Primärschlüssel:Hier wird es interessant. Sie können
IDENTITY_INSERT
für die Tabelle aktivieren. Dies bedeutet, dass Sie die Werte einerIDENTITY
Spalte manuell definieren können, wenn Sie neue Zeilen einfügen (jedoch keine vorhandenen Zeilen aktualisieren).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 dieid
Spalte (aus der Sicherungsspalte).Sobald Sie fertig sind, schalten Sie ihn
IDENTITY_INSERT
wieder aus.Löschen Sie die temporäre Spalte, die wir hinzugefügt haben:
Und schließlich die
IDENTITY
Spalte neu auslegen , damit die nächsten Datensätzeid
nach der höchsten vorhandenen Nummer in derid
Spalte fortgesetzt werden :In der Beispieltabelle ist die höchste
id
Zahl 20.Fügen Sie eine weitere Zeile hinzu und überprüfen Sie die neue
IDENTITY
:Im Beispiel wird die neue Zeile haben
id=21
. Wenn Sie zufrieden sind, führen Sie die Transaktion aus: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
undDELETE
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:
id
Spalte alsIDENTITY
,IDENTITY_INSERT ON
für den Tisch,IDENTITY_INSERT OFF
undquelle
IDENTITY_INSERT ON
, auffüllen und deaktivieren. Das wollte ich tun, wusste aber nicht, dass MSSQL es unterstützt.Das Verschieben von Daten mit UPDATE, DELETE oder INSERT kann viel Zeit in Anspruch nehmen und Ressourcen (IO) auf Daten- und Protokolldateien / -datenträgern belegen. Es ist möglich, zu vermeiden, dass das Transaktionsprotokoll bei der Arbeit an einer großen Tabelle mit möglicherweise vielen Datensätzen gefüllt wird: Beim Partitionswechsel werden nur die Metadaten geändert.
Es ist keine Datenverschiebung erforderlich, und dies erfolgt daher sehr schnell (fast augenblicklich).
Probentabelle
Die Frage zeigt nicht die ursprüngliche Tabelle DDL. Die folgende DDL wird in dieser Antwort als Beispiel verwendet:
Ein halbes Dutzend zufällige Dummy-IDs von 0 bis 15 werden mit dieser Abfrage hinzugefügt:
Beispieldaten in
IdT
Neuer Tisch mit
IDENTITY(0, 1)
Das einzige Problem
idT
ist das Fehlen derIDENTITY(0, 1)
Eigenschaft auf ID. Eine neue Tabelle mit einer ähnlichen StrukturIDENTITY(0, 1)
wird erstellt:Abgesehen davon
IDENTITY(0, 1)
,idT_Switch
ist identischidT
.Fremde Schlüssel
Fremdschlüssel an
idT
müssen entfernt werden, damit diese Technik verwendet werden kann.Partitionsschalter
Die Tabellen
idT
undidT_Switch
haben eine kompatible Struktur. Anstelle der VerwendungDELETE
,UPDATE
undINSERT
Aussagen Zeilen verschieben vonidT
zuidT_Switch
oder aufidT
sich selbst,ALTER TABLE ... SWITCH
können verwendet werden:Die einzelne 'Partition' von
PK_idT
(der gesamten Tabelle) wird nachPK_idT_Switch
(und umgekehrt) verschoben .idT
enthält jetzt 0 Zeilen undidT_Switch
enthält 6 Zeilen.Die vollständige Liste der Quell- und Zielkompatibilitätsanforderungen finden Sie hier:
Effiziente Datenübertragung mit Partition Switching
Beachten Sie, dass für diese Verwendung von
SWITCH
keine Enterprise Edition erforderlich ist, da keine explizite Partitionierung erfolgt. Eine nicht partitionierte Tabelle wird ab SQL Server 2005 als Tabelle mit einer einzelnen Partition betrachtet.Ersetzen
idT
idT
ist jetzt leer und unbrauchbar und kann fallengelassen werden:idT_Switch
kann umbenannt werden und ersetzt die alteidT
Tabelle:Fremde Schlüssel
Der neuen
idT
Tabelle können wieder Fremdschlüssel hinzugefügt werden . Alles, was zuvor entfernt wurdeidT
, um die Tabellen für den Wechsel kompatibel zu machen, muss ebenfalls wiederholt werden.Reseed
Dieser Befehl gibt 0 zurück. Die Tabelle idT enthält 6 Zeilen mit MAX (id) = 15. DBCC CHECKIDENT (table_name) kann verwendet werden:
Da 15 größer als 0 ist, wird die Saat automatisch wiederholt, ohne nach MAX (id) zu suchen:
IDENT_CURRENT gibt jetzt 15 zurück .
Testen und Daten hinzufügen
Eine einfache
INSERT
Aussage:Fügt diese Zeile hinzu:
Die
id
Spalte verwendet jetzt die Identität und der neu eingefügte Wert ist tatsächlich 16 (15 + 1).Mehr Informationen
Hier gibt es eine verwandte Frage und Antwort mit mehr Hintergrundinformationen zur
SWITCH
Technik:Warum wird das Entfernen der Identity-Eigenschaft für eine Spalte nicht unterstützt?
quelle
Wenn Sie mit einem neuen Identitätswert beginnen möchten, müssen Sie Ihre Identität erneut überprüfen. Schauen Sie sich die Dokumentation für an
CHECKIDENT
quelle
ENABLE und DISABLE IDENTITY_INSERT
Wenn Ihre Tabelle dann TABLE_A ist
quelle