Wie aktualisiere ich die Identitätsspalte in SQL Server?

194

Ich habe eine SQL Server-Datenbank und möchte die Identitätsspalte ändern, da sie mit einer großen Zahl begann und mit einer 10010anderen Tabelle verknüpft ist. Jetzt habe ich 200 Datensätze und möchte dieses Problem beheben, bevor die Datensätze zunehmen.

Wie kann diese Spalte am besten geändert oder zurückgesetzt werden?

Abdulsalam Elsharif
quelle

Antworten:

269

Sie können die Identitätsspalte nicht aktualisieren.

In SQL Server kann die Identitätsspalte nicht aktualisiert werden, anders als bei anderen Spalten mit einer Update-Anweisung.

Es gibt zwar einige Alternativen, um eine ähnliche Anforderung zu erfüllen.

  • Wenn der Wert der Identitätsspalte für neue Datensätze aktualisiert werden muss

Verwenden Sie DBCC CHECKIDENT, das den aktuellen Identitätswert für die Tabelle überprüft und bei Bedarf den Identitätswert ändert.

DBCC CHECKIDENT('tableName', RESEED, NEW_RESEED_VALUE)
  • Wenn der Wert der Identitätsspalte für vorhandene Datensätze aktualisiert werden muss

Verwenden Sie IDENTITY_INSERT , mit dem explizite Werte in die Identitätsspalte einer Tabelle eingefügt werden können.

SET IDENTITY_INSERT YourTable {ON|OFF}

Beispiel:

-- Set Identity insert on so that value can be inserted into this column
SET IDENTITY_INSERT YourTable ON
GO
-- Insert the record which you want to update with new value in the identity column
INSERT INTO YourTable(IdentityCol, otherCol) VALUES(13,'myValue')
GO
-- Delete the old row of which you have inserted a copy (above) (make sure about FK's)
DELETE FROM YourTable WHERE ID=3
GO
--Now set the idenetity_insert OFF to back to the previous track
SET IDENTITY_INSERT YourTable OFF
Sachin
quelle
6
DBCC Setzt den nächsten neuen Datensatz zurück, aber was ich jetzt möchte, um die vorhandenen Datensätze zu ändern.
Abdulsalam Elsharif
Können Sie bitte ein Beispiel geben?
Abdulsalam Elsharif
38
@sachin dies aktualisiert nicht eine vorhandene IDENTITÄT, die manuell eingefügt wird
Phill Greggan
3
@PhillGreggan Ja, dies ist die bestmögliche Lösung, um dies zu erreichen. Sie können die Identitätsspalte nicht aktualisieren, da Sie die normalen Spalten aktualisieren.
Sachin
17
Diese akzeptierte Antwort beantwortet nicht die Frage, wie eine Identitätsspalte aktualisiert werden soll (z UPDATE YourTable SET IdentityCol = 13. B. ). SET IDENTITY_INSERT YourTable ONerlaubt nur INSERTs, keine UPDATEs.
Ian Boyd
61

Wenn Sie Ihre Frage richtig gestellt haben, möchten Sie so etwas tun

update table
set identity_column_name = some value

Lassen Sie mich Ihnen sagen, es ist kein einfacher Prozess und es ist nicht ratsam, ihn zu verwenden, da möglicherweise einige damit foreign keyverbunden sind.

Aber hier sind Schritte, um es zu tun. Bitte nehmen Sie einen back-upTisch

Schritt 1- Wählen Sie die Entwurfsansicht der Tabelle aus

Geben Sie hier die Bildbeschreibung ein

Schritt 2- Deaktivieren Sie die Identitätsspalte

Geben Sie hier die Bildbeschreibung ein

Jetzt können Sie die updateAbfrage verwenden.

Nun redodie Schritte 1 und 2 und Aktivieren Sie die Identitätsspalte

Referenz

Luv
quelle
1
Ich habe einen anderen Tisch, der mit diesem Tisch zusammenhängt, ich glaube, das kann ich nicht
Abdulsalam Elsharif
4
Daher ist die Aussage nicht ratsam :)
Luv
3
@AbdusalamElsherif Sie haben jedoch gefragt, wie die Identitätsspalte geändert werden soll.
Paparazzo
@luv zumindest haben Sie auf die gestellte Frage geantwortet
Phill Greggan
Ich verwende dieses Verfahren zum Festlegen der ID in meiner Entwicklungsdatenbank. Es wäre schön, wenn es einen Befehl gäbe, mit dem ich es trotzdem tun könnte, aber das funktioniert.
Jeff Davis
56

Du brauchst

set identity_insert YourTable ON

Löschen Sie dann Ihre Zeile und fügen Sie sie mit einer anderen Identität wieder ein.

Vergessen Sie nach dem Einfügen nicht, identity_insert zu deaktivieren

set identity_insert YourTable OFF
RSP
quelle
Dies ist so viel einfacher und sicherer als das Deaktivieren der Identität für die Spalte!
Beschützer ein
Dies ist sicherer und für eine kleine Anzahl von Datensätzen einfach, beantwortet die Frage jedoch nicht richtig. Das Deaktivieren der Identität ist zwar gefährlicher und manchmal unmöglich, ermöglicht Ihnen jedoch das Aktualisieren der Identitätsspalte.
Matthew Hudson
18
--before running this make sure Foreign key constraints have been removed that reference the ID. 

--set table to allow identity to be inserted
SET IDENTITY_INSERT yourTable ON;
GO
--insert everything into a temp table
SELECT * 
INTO #tmpYourTable
FROM yourTable

--clear your table
DELETE FROM yourTable
--insert back all the values with the updated ID column
INSERT INTO yourTable (IDCol, OtherCols)
SELECT ID+1 as updatedID --put any other update logic to the ID here
, OtherCols FROM #tmpYourTable
--drop the temp table
DROP TABLE #tmpYourTable
--put identity back to normal
SET IDENTITY_INSERT yourTable OFF;
GO
kuklei
quelle
1
Nur ein Leistungstipp, wenn die Tabelle sehr groß ist, anstatt eine Tabelle zu löschen, führen Sie eine Tabelle zum Abschneiden Ihrer Tabelle aus. Es ist augenblicklich. Achtung, kein Zurück mit Abschneiden, da es nicht protokolliert wird.
Kuklei
5

Kopieren Sie Ihre Tabelle in eine neue Tabelle ohne Identitätsspalte.

    select columns into newtable from yourtable

Fügen Sie der Newtable eine Identitätsspalte mit neuem Startwert hinzu und legen Sie sie als Primärschlüssel fest

    ALTER TABLE tableName ADD id MEDIUMINT NOT NULL AUTO_INCREMENT KEY
user4002899
quelle
3
DBCC CHECKIDENT(table_name, RESEED, value)

table_name = Geben Sie die Tabelle an, deren Wert Sie zurücksetzen möchten

value = Anfangswert ist Null, um die Identitätsspalte mit 1 zu beginnen

Yasmeen Ansari
quelle
3
SET IDENTITY_INSERT dbo.TableName ON
INSERT INTO dbo.TableName 
(
    TableId, ColumnName1, ColumnName2, ColumnName3
)
VALUES
(
    TableId_Value, ColumnName1_Value, ColumnName2_Value, ColumnName3_Value
)

SET IDENTITY_INSERT dbo.TableName OFF

Vergessen Sie bei der Verwendung von Identity_Insert nicht, die Spaltennamen anzugeben, da Sie mit SQL nicht einfügen können, ohne sie anzugeben

befree2j
quelle
2

Sie können auch verwenden SET IDENTITY INSERT , um Werte in eine Identitätsspalte einzufügen.

Beispiel:

SET IDENTITY_INSERT dbo.Tool ON
GO

Anschließend können Sie die benötigten Werte in eine Identitätsspalte einfügen.

DaveShaw
quelle
1
ALTER TABLE tablename add newcolumn int
update tablename set newcolumn=existingcolumnname
ALTER TABLE tablename DROP COLUMN existingcolumnname;
EXEC sp_RENAME 'tablename.oldcolumn' , 'newcolumnname', 'COLUMN'
update tablename set newcolumnname=value where condition

Der obige Code funktioniert jedoch nur, wenn keine Primär-Fremdschlüssel-Beziehung besteht

Jekin Kalariya
quelle
1

Komplettlösung für C # -Programmierer mit Command Builder

Zuallererst müssen Sie diese Fakten kennen:

  • In jedem Fall können Sie eine Identitätsspalte nicht ändern, daher müssen Sie die Zeile löschen und mit neuer Identität erneut hinzufügen.
  • Sie können die Identitätseigenschaft nicht aus der Spalte entfernen (Sie müssten sie in die Spalte entfernen).
  • Der benutzerdefinierte Befehlsgenerator von .net überspringt immer die Identitätsspalte, sodass Sie sie nicht für diesen Zweck verwenden können.

Wenn Sie das wissen, müssen Sie es tun. Programmieren Sie entweder Ihre eigene SQL Insert-Anweisung oder Ihren eigenen Insert Command Builder. Oder verwenden Sie diese, die ich für Sie programmiert habe. Generiert bei einer gegebenen DataTable das SQL Insert-Skript:

public static string BuildInsertSQLText ( DataTable table )
{
    StringBuilder sql = new StringBuilder(1000,5000000);
    StringBuilder values = new StringBuilder ( "VALUES (" );
    bool bFirst = true;
    bool bIdentity = false;
    string identityType = null;

    foreach(DataRow myRow in table.Rows) 
    {
        sql.Append( "\r\nINSERT INTO " + table.TableName + " (" );

        foreach ( DataColumn column in table.Columns )
        {
            if ( column.AutoIncrement )
            {
                bIdentity = true;

                switch ( column.DataType.Name )
                {
                    case "Int16":
                        identityType = "smallint";
                        break;
                    case "SByte":
                        identityType = "tinyint";
                        break;
                    case "Int64":
                        identityType = "bigint";
                        break;
                    case "Decimal":
                        identityType = "decimal";
                        break;
                    default:
                        identityType = "int";
                        break;
                }
            }
            else
            {
                if ( bFirst )
                    bFirst = false;
                else
                {
                    sql.Append ( ", " );
                    values.Append ( ", " );
                }
                sql.Append ("[");
                sql.Append ( column.ColumnName );
                sql.Append ("]");

                //values.Append (myRow[column.ColumnName].ToString() );

                if (myRow[column.ColumnName].ToString() == "True")
                    values.Append("1");
                else if (myRow[column.ColumnName].ToString() == "False")
                    values.Append("0");
                else if(myRow[column.ColumnName] == System.DBNull.Value)    
                    values.Append ("NULL");
                else if(column.DataType.ToString().Equals("System.String"))
                {
                    values.Append("'"+myRow[column.ColumnName].ToString()+"'");
                }
                else
                    values.Append (myRow[column.ColumnName].ToString());
                    //values.Append (column.DataType.ToString() );
            }
        }
        sql.Append ( ") " );
        sql.Append ( values.ToString () );
        sql.Append ( ")" );

        if ( bIdentity )
        {
            sql.Append ( "; SELECT CAST(scope_identity() AS " );
            sql.Append ( identityType );
            sql.Append ( ")" );
        }
        bFirst = true;
        sql.Append(";");
        values = new StringBuilder ( "VALUES (" );
    } //fin foreach
    return sql.ToString ();
}
Juan_Mallorca
quelle
0

Ich habe dieses Problem zuerst mit DBCC und dann mit Insert gelöst. Zum Beispiel, wenn Ihre Tabelle ist

Legen Sie zunächst den neuen aktuellen ID-Wert in der Tabelle als NEW_RESEED_VALUE fest

MyTable {IDCol, colA, colB}

    DBCC CHECKIDENT('MyTable', RESEED, NEW_RESEED_VALUE)

dann kannst du verwenden

    insert into MyTable (colA, ColB) select colA, colB from MyTable

Dies würde alle Ihre Datensätze duplizieren, aber einen neuen IDCol-Wert verwenden, der mit NEW_RESEED_VALUE beginnt. Sie können dann doppelte Zeilen mit höherem ID-Wert entfernen, sobald Sie deren Fremdschlüsselreferenzen entfernt / verschoben haben, falls vorhanden.

Softec
quelle
1
Dies ist eine anständige Idee, aber der New_reseed_value ist der aktuelle Startwert, und die nächste Zahl, die verwendet wird, ist 1 mehr als dieser Wert. Wenn Sie also möchten, dass die nächste eingefügte Zeile die Identität 10 hat, muss NEW_RESEED_VALUE auf 9 gesetzt werden.
LarryBud
0

Mit dem folgenden Code können Sie eine neue Tabelle erstellen.

SELECT IDENTITY (int, 1, 1) AS id, column1, column2
INTO dbo.NewTable
FROM dbo.OldTable

Löschen Sie dann die alte Datenbank und benennen Sie die neue Datenbank in den Namen der alten Datenbank um. Hinweis : Spalte1 und Spalte2 stellen alle Spalten in Ihrer alten Tabelle dar, die Sie in Ihrer neuen Tabelle behalten möchten.

Sean H. Worthington
quelle
0

Wenn Sie den Primärschlüsselwert speziell in eine andere Zahl ändern müssen (z. B. 123 -> 1123). Die Identitätseigenschaft blockiert das Ändern eines PK-Werts. Set Identity_insert wird nicht funktionieren. Das Einfügen / Löschen ist nicht ratsam, wenn Sie kaskadierende Löschvorgänge haben (es sei denn, Sie deaktivieren die Überprüfung der referenziellen Integrität).

Dieses Skript deaktiviert die Identität einer PK:

***********************

sp_configure 'allow update', 1
go
reconfigure with override
go


update syscolumns set colstat = 0 --turn off bit 1 which indicates identity column
where id = object_id('table_name') and name = 'column_name'
go


exec sp_configure 'allow update', 0
go
reconfigure with override
go

***********************

Als Nächstes können Sie die Beziehungen so einstellen, dass sie die Fremdschlüsselreferenzen aktualisieren. Oder Sie müssen die Durchsetzung von Beziehungen deaktivieren. Dieser SO-Link zeigt, wie: Wie können Fremdschlüsseleinschränkungen mithilfe von T-SQL vorübergehend deaktiviert werden?

Jetzt können Sie Ihre Updates durchführen. Ich habe ein kurzes Skript geschrieben, um alle meine Update-SQLs mit demselben Spaltennamen zu schreiben (in meinem Fall musste ich die CaseID um 1.000.000 erhöhen:

select 
'update ['+c.table_name+'] SET ['+Column_Name+']=['+Column_Name+']+1000000'
from Information_Schema.Columns as c
JOIN Information_Schema.Tables as t ON t.table_Name=c.table_name and t.Table_Schema=c.table_schema and t.table_type='BASE TABLE'
where Column_Name like 'CaseID' order by Ordinal_position

Zuletzt aktivieren Sie die referenzielle Integrität erneut und aktivieren Sie dann die Spalte Identität auf dem Primärschlüssel erneut.

Hinweis: Ich sehe einige Leute bei diesen Fragen fragen, warum. In meinem Fall muss ich Daten von einer zweiten Produktionsinstanz in eine Master-Datenbank zusammenführen, damit ich die zweite Instanz herunterfahren kann. Ich brauche nur alle PK / FKs der Betriebsdaten, um nicht zu kollidieren. Metadaten-FKs sind identisch.

Ken Forslund
quelle