SQL Server'da Kimlik Sütunu nasıl güncelleştirilir?


196

SQL Server veritabanı var ve ben büyük bir sayı ile başladı 10010ve başka bir tablo ile ilgili, çünkü şimdi 200 kayıtları var kimlik sütununu değiştirmek istiyorum ve kayıtları artmadan önce bu sorunu düzeltmek istiyorum.

Bu sütunu değiştirmenin veya sıfırlamanın en iyi yolu nedir?

Yanıtlar:


270

Kimlik sütununu güncelleyemezsiniz.

SQL Server, güncelleme sütunuyla diğer sütunlarda yapabileceklerinizin aksine kimlik sütununu güncellemeye izin vermez.

Benzer bir gereksinimi elde etmek için bazı alternatifler olmasına rağmen.

  • Yeni kayıtlar için Kimlik sütunu değerinin güncellenmesi gerektiğinde

Tablo için geçerli kimlik değerini denetleyen DBCC CHECKIDENT kullanın ve gerekirse kimlik değerini değiştirir.

DBCC CHECKIDENT('tableName', RESEED, NEW_RESEED_VALUE)
  • Mevcut kayıtlar için Kimlik sütun değerinin güncellenmesi gerektiğinde

Bir tablonun kimlik sütununa açık değerlerin eklenmesine izin veren IDENTITY_INSERT kullanın .

SET IDENTITY_INSERT YourTable {ON|OFF}

Misal:

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

6
DBCC Bir sonraki yeni kaydı sıfırlayın, ancak şimdi varolan kayıtları değiştirmek için ne istiyorum.
Abdulsalam Elsharif

örnek verebilir misiniz lütfen
Abdulsalam Elsharif

38
@sachin bu, el ile
ekleyen

3
@PhillGreggan evet, bunu başarmak için mümkün olan en iyi çözüm budur. Normal sütunları güncellediğiniz için Kimlik sütununu güncelleyemezsiniz.
Sachin

17
Kabul edilen bu cevap, bir kimlik sütununu (ör. ) Nasıl güncelleyeceğiniz sorusuna cevap vermez UPDATE YourTable SET IdentityCol = 13. SET IDENTITY_INSERT YourTable ONsadece INSERT'lere izin verir, UPDATE'lere izin vermez.
Ian Boyd

62

Sorunuz doğru ise, böyle bir şey yapmak istersiniz

update table
set identity_column_name = some value

Size söyleyeyim, bu kolay bir süreç değil ve foreign keyüzerinde bir şeyler olabileceği için kullanılması tavsiye edilmez .

Ama burada yapılması gereken adımlar, Lütfen back-uptabloyu alın

Adım 1- Tablonun tasarım görünümünü seçin

resim açıklamasını buraya girin

Adım 2- Kimlik sütununu kapatın

resim açıklamasını buraya girin

Şimdi updatesorguyu kullanabilirsiniz .

Şimdi redoadım 1 ve adım 2 ile Kimlik sütununu aç

Referans


1
Bu tabloyla ilgili başka bir masam var, bunu yapamam
Abdulsalam Elsharif

4
Bu nedenle tavsiye edilmez :)
Luv

3
@AbdusalamElsherif Ama kimlik sütununu nasıl değiştireceğinizi sordunuz.
paparazzo

@luv en azından sorulan soruya cevap
verdiniz

Geliştirme veritabanımdaki kimliği ayarlamak için bu yordamı kullanın. Yine de yapmama izin veren bir komut olsaydı iyi olurdu, ama bu işe yarıyor.
Jeff Davis

56

Gerek

set identity_insert YourTable ON

Ardından satırınızı silin ve farklı bir kimlikle yeniden yerleştirin.

Ekleme işlemini yaptıktan sonra identity_insert'i kapatmayı unutmayın

set identity_insert YourTable OFF

Bu sütun için Kimlik'i kapatmaktan çok daha kolay ve güvenlidir!
Koruyucu bir

Bu, daha az sayıda kayıt için daha güvenli ve kolaydır, ancak soruyu doğru bir şekilde cevaplamaz. Kimliğin kapatılması, daha tehlikeli ve bazen imkansız olsa da, kimlik sütununu güncellemenizi sağlar.
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

1
Sadece bir performans ipucu tablo çok büyükse, tablo üzerinde bir silme yapmak yerine bir Kesme Tablo yourTable yapın. Anlıktır. Yine de, günlüğe kaydedilmediğinden kesik ile geri dönüş yok.
kuklei


5

tablonuzu kimlik sütunu olmadan yeni bir tabloya kopyalayın.

    select columns into newtable from yourtable

yeni tohumla yenisine bir kimlik sütunu ekleyin ve birincil anahtar olarak yapın

    ALTER TABLE tableName ADD id MEDIUMINT NOT NULL AUTO_INCREMENT KEY

3
DBCC CHECKIDENT(table_name, RESEED, value)

table_name = değeri sıfırlamak istediğiniz tabloyu verin

value = kimlik sütununu 1 ile başlatmak için sıfır olmak üzere başlangıç ​​değeri


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

Identity_Insert kullanırken sütun adlarını eklemeyi unutmayın, çünkü sql belirtmeden eklemenize izin vermez


2

SET IDENTITY INSERTKimlik sütununa değer eklemenize izin vermek için de kullanabilirsiniz .

Misal:

SET IDENTITY_INSERT dbo.Tool ON
GO

Ve sonra ihtiyacınız olan değerleri bir kimlik sütununa ekleyebilirsiniz.


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

Ancak yukarıdaki kod yalnızca birincil-yabancı anahtar ilişkisi yoksa çalışır


1

Komut oluşturucu kullanarak C # programcıları için eksiksiz çözüm

Her şeyden önce, bu gerçekleri bilmelisiniz:

  • Her durumda, bir kimlik sütununu değiştiremezsiniz, bu nedenle satırı silmeniz ve yeni bir kimlikle yeniden eklemeniz gerekir.
  • İdentity özelliğini sütundan kaldıramazsınız (sütuna kaldırmanız gerekir)
  • .Net'teki özel komut oluşturucu her zaman kimlik sütununu atlar, bu nedenle bu amaçla kullanamazsınız.

Yani, bunu bildikten sonra yapmanız gereken şey. Kendi SQL Insert deyiminizi veya kendi insert komut oluşturucunuzu programlayın. Ya da senin için programladığım bunu kullan. DataTable verildiğinde SQL Insert komut dosyasını oluşturur:

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 ();
}

0

Öncelikle DBCC kullanarak ve sonra insert kullanarak bu sorunu çözdüm. Örneğin, tablonuz

Öncelikle tabloda yeni geçerli Kimlik Değerini NEW_RESEED_VALUE olarak ayarlayın

MyTable {IDCol, colA, colB}

    DBCC CHECKIDENT('MyTable', RESEED, NEW_RESEED_VALUE)

o zaman kullanabilirsiniz

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

Bu, tüm kayıtlarınızı çoğaltır ancak NEW_RESEED_VALUE olarak başlayan yeni IDCol değeri kullanır. Daha sonra, varsa yabancı anahtar referanslarını kaldırdıktan / taşıdıktan sonra daha yüksek Kimlik Değeri yinelenen satırlarını kaldırabilirsiniz.


1
Bu iyi bir fikir, ancak New_reseed_value geçerli tohumdur ve kullanılacak bir sonraki sayı bu değerden 1 daha fazla olacaktır. Bu nedenle, bir sonraki eklenen satırın kimlik 10 olmasını istiyorsanız, NEW_RESEED_VALUE değeri 9 olarak ayarlanmalıdır.
LarryBud

0

Aşağıdaki kodu kullanarak yeni bir tablo oluşturabilirsiniz.

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

Ardından eski db'yi silin ve yeni db'yi eski db'nin adıyla yeniden adlandırın. Not : bu sütun1 ve sütun2, eski tablonuzdaki yeni tablonuzda tutmak istediğiniz tüm sütunları temsil eder.


0

Birincil anahtar değerini özellikle farklı bir sayıya değiştirmeniz gerekiyorsa (ör. 123 -> 1123). İdentity özelliği bir PK değerini değiştirmeyi engeller. Set Identity_insert işe yaramayacak. Basamaklı silme işlemleriniz varsa (başvuru bütünlüğü denetimini kapatmadıysanız) Ekle / Sil işlemi önerilmez.

Bu komut dosyası bir PK üzerindeki kimliği kapatır:

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

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

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

Daha sonra ilişkileri, yabancı anahtar referanslarını güncelleyecek şekilde ayarlayabilirsiniz. Aksi takdirde ilişki yürütmeyi kapatmanız gerekir. Bu SO bağlantısı nasıl gösterir: Yabancı anahtar kısıtlamaları T-SQL kullanarak geçici olarak nasıl devre dışı bırakılabilir?

Şimdi güncellemelerinizi yapabilirsiniz. Tüm güncelleme SQL'imi aynı sütun adına göre yazmak için kısa bir komut dosyası yazdım (benim durumumda, CaseID'yi 1.000.000 artırmam gerekiyordu:

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

Son olarak, başvuru bütünlüğünü yeniden etkinleştirin ve ardından birincil anahtardaki Kimlik sütununu yeniden etkinleştirin.

Not: Bu sorulardaki bazı kişilerin NEDEN diye sorduğunu görüyorum. Benim durumumda, ikinci bir üretim örneğindeki verileri bir ana DB'ye birleştirmem gerekiyor, böylece ikinci örneği kapatabiliyorum. Çarpışmamak için sadece operasyon verilerinin tüm PK / FK'larına ihtiyacım var. Meta veri FK'leri aynıdır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.