Tablodaki bir sütundan Kimliği kaldırma


127

5GB'lık bir tablomuz var (yaklaşık 500 milyon satır) ve bir sütundaki kimlik özelliğini kaldırmak istiyoruz, ancak bunu SSMS aracılığıyla yapmaya çalıştığımızda - zaman aşımına uğruyor.

Bu T-SQL ile yapılabilir mi?


1
Tablonun şemasını buraya gönderebilir misiniz?
Al W

Eminim SQL Server'ın bir kimlik özelliğini basit bir ALTER TABLE ... ifadesi aracılığıyla bir sütundan kaldırmayı desteklememesinin mükemmel nedenleri vardır, ancak yine de durum şu anda beni üzüyor.
Jon Schneider

Yanıtlar:


143

Bir IDENTITYspesifikasyonu ayarladıktan sonra kaldıramazsınız .

Tüm sütunu kaldırmak için:

ALTER TABLE yourTable
DROP COLUMN yourCOlumn;

ALTER TABLE hakkında bilgi burada

Verileri tutmanız, ancak IDENTITYsütunu kaldırmanız gerekirse , yapmanız gerekenler:

  • Yeni bir sütun oluştur
  • Verileri mevcut IDENTITYsütundan yeni sütuna aktarın
  • Mevcut IDENTITYsütunu bırakın .
  • Yeni sütunu orijinal sütun adıyla yeniden adlandırın

3
bir Kimlik özelliğini kaldırabilirsiniz. Aslında bunu dün 500 milyon satırda olmasa da SSMS kullanarak yapmak zorunda kaldım.
Simon

34
@simon, değişikliklerinizi komut dosyası haline getirirseniz, SSMS'nin aslında kimlik özelliği olmadan tablonun bir kopyasını oluşturduğunu görürsünüz.
Code Magician

3
Sadece yeni sütunu orijinal sütunun adına yeniden adlandırmak için eklemek istiyorum. Ayrıca, bu identitysütun foreign keybaşka bir tablodaki bir tablonun parçası olarak kullanılıyorsa, önce kısıtlamaları kaldırmanız, ardından @AdamWenger'ın kimliğin kaldırılmasıyla ilgili bahsettiği gibi harekete geçmeniz gerekecektir attribute/property. Daha fazla ayrıntı için bu bağlantıya da bakabilirsiniz. yalnızca özniteliğin kaldırılması hakkında: blog.sqlauthority.com/2009/05/03/… .. İyi şanslar!
Nonym

1
Olumsuz oy kullanan kişiye - cevabımla ilgili hoşunuza gitmeyen şeyleri duymaktan memnun olurum.
Adam Wenger

1
Aşağıdaki Mark Sowul'un cevabına bir göz atın. Verileri sütundan sütuna taşıma ihtiyacını ortadan kaldırır. Mark'ın yanıtını kullanarak yalnızca meta verileri karıştırıyorsunuz. Onlarca veya yüz milyonlarca satırı olan bir tablo üzerinde çalışmadığınız sürece önemli değil. Artı Mark'ın cevabı, tablo şemasında sütunun yeniden konumlandırılmasını engeller. Sadece denedim ve harika çalıştı. Çok zeki.
Andrew Steitz

100

Bunu yapmak istiyorsanız eklenmesi ve yeni bir sütun doldurma olmadan , sütunları yeniden sıralama olmadan ve neredeyse hiç kesinti ile hiçbir bölümleri kullanıldığından veri masaya değişiyor, çünkü izin işlevselliği bölümleme ile bazı büyü yapmak (ancak 'don Enterprise sürümüne ihtiyacınız var):

  1. Bu tabloya işaret eden tüm yabancı anahtarları kaldırın
  2. Oluşturulacak tabloyu kodlayın; her şeyi yeniden adlandırın, örneğin 'MyTable2', 'MyIndex2', vb. KİMLİK belirtimini kaldırın.
  3. Şimdi, biri dolu, diğeri KİMLİK içermeyen iki "özdeş" tablonuz olmalıdır.
  4. Çalıştırmak ALTER TABLE [Original] SWITCH TO [Original2]
  5. Şimdi orijinal tablonuz boş olacak ve yenisi verilere sahip olacak. İki tablonun meta verilerini değiştirdiniz (anında).
  6. exec sys.sp_renameÇeşitli şema nesnelerini orijinal adlarıyla yeniden adlandırmak için orijinali (artık boş olan tabloyu) bırakın ve ardından yabancı anahtarlarınızı yeniden oluşturabilirsiniz.

Örneğin, verilen:

CREATE TABLE Original
(
  Id INT IDENTITY PRIMARY KEY
, Value NVARCHAR(300)
);
CREATE NONCLUSTERED INDEX IX_Original_Value ON Original (Value);

INSERT INTO Original
SELECT 'abcd'
UNION ALL 
SELECT 'defg';

Aşağıdakileri yapabilirsiniz:

--create new table with no IDENTITY
CREATE TABLE Original2
(
  Id INT PRIMARY KEY
, Value NVARCHAR(300)
);
CREATE NONCLUSTERED INDEX IX_Original_Value2 ON Original2 (Value);

--data before switch
SELECT 'Original', *
FROM Original
UNION ALL
SELECT 'Original2', *
FROM Original2;

ALTER TABLE Original SWITCH TO Original2;

--data after switch
SELECT 'Original', *
FROM Original
UNION ALL
SELECT 'Original2', *
FROM Original2;

--clean up 
IF NOT EXISTS (SELECT * FROM Original) DROP TABLE Original;
EXEC sys.sp_rename 'Original2.IX_Original_Value2', 'IX_Original_Value', 'INDEX';
EXEC sys.sp_rename 'Original2', 'Original', 'OBJECT';


UPDATE Original
SET Id = Id + 1;

SELECT *
FROM Original;

Bunu gerçekten denemek için vaktim yok, ama bir dahaki sefere gerçekten bir kimliği bırakmam gerektiğini bilmek iyi bir şey.
CoderDennis

12
Kabul edilen cevap bu olmalıdır. Bir kimlik sütununu büyük miktarda veri geçişi olmadan kaldırmanın tek gerçek yolu budur.
Vaccano

Vaov! Bu çok zekice.
Andrew Steitz

Bu cevap olağanüstü! Teşekkürler!
Jon

5
Tabloyu komut dosyası oluşturmak için SQL Management Studio kullanıyorsanız, Araçlar> Seçenekler> SQL Server Nesne Gezgini> Komut Dosyası> Tablo ve seçenekleri görüntüle> Komut dosyası dizinlerini (varsayılan olarak Yanlış)
user423430

61

Bu, yabancı ve birincil anahtar kısıtlamalarıyla karışır, işte size yolunuzda yardımcı olacak bazı komut dosyaları:

İlk olarak, geçici bir ada sahip bir yinelenen sütun oluşturun:

alter table yourTable add tempId int NOT NULL default -1;
update yourTable set tempId = id;

Ardından, birincil anahtar kısıtlamanızın adını alın:

SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'yourTable';

Şimdi sütununuz için birincil anahtar kısıtlamasını kaldırmayı deneyin:

ALTER TABLE yourTable DROP CONSTRAINT PK_yourTable_id;

Yabancı anahtarlarınız varsa başarısız olur, öyleyse yabancı anahtar kısıtlamalarını kaldırın. KISITLAMALARI DAHA SONRA GERİ EKLEMEK İÇİN BUNU ÇALIŞTIRDIĞINIZ TABLOLARI TAKİP EDİN !!!

SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'otherTable';
alter table otherTable drop constraint fk_otherTable_yourTable;
commit;
..

Tüm yabancı anahtar kısıtlamalarınız kaldırıldıktan sonra, PK kısıtlamasını kaldırabilir, bu sütunu bırakabilir, geçici sütununuzu yeniden adlandırabilir ve bu sütuna PK kısıtlamasını ekleyebilirsiniz:

ALTER TABLE yourTable DROP CONSTRAINT PK_yourTable_id;
alter table yourTable drop column id;
EXEC sp_rename 'yourTable.tempId', 'id', 'COLUMN';
ALTER TABLE yourTable ADD CONSTRAINT PK_yourTable_id PRIMARY KEY (id) 
commit;

Son olarak, FK kısıtlamalarını tekrar ekleyin:

alter table otherTable add constraint fk_otherTable_yourTable foreign key (yourTable_id) references yourTable(id);
..

El Fin!


sql sunucu sürümünüze dikkat edin, azure sql sunucusunda denedim, buradaki tüm işlemler azure version sql'de desteklenmiyor.
dasons

Cevap için teşekkürler! Bana çok yardım etti! Sadece sütuna başvuran dizinler için bir doğrulama eklemelisiniz. Şunun gibi bir şey: Select t.name 'Table', i.name 'Index', c.name 'Column', i.is_primary_key, i.is_unique From sys.tables t Inner Join sys.indexes i On i.object_id = t.object_id Inner Join sys.index_columns ic ON ic.object_id = i.object_id And i.index_id = ic.index_id Inner Join sys.columns c ON ic.object_id = c.object_id and ic.column_id = c.column_id Where t.name = 'tableName' Order By t.name, i.name, i.index_id, ic.index_column_id
Alexandre Junges

iyi bir numara, bana çok yardımcı oldu, Ama bir nokta, burada bahsetmek istiyorum ki, 1. adımda belirtildiği gibi yeni bir mükerrer sütun eklediğimizde, sonuna eklendi, ancak genellikle birincil anahtar sütunumuzun yani Id'nin bu tablodaki 1. sütun. Peki bunun için herhangi bir geçici çözüm var mı?
Ashish Shukla

19

Ben de aynı sorunu yaşadım. GUI kullanmak yerine SSMS'de 4 ifade ve çok hızlıydı.

  • Yeni bir sütun oluştur

    alter table users add newusernum int;

  • Değerleri kopyala

    update users set newusernum=usernum;

  • Eski sütunu bırak

    alter table users drop column usernum;

  • Yeni sütunu eski sütun adıyla yeniden adlandırın

    EXEC sp_RENAME 'users.newusernum' , 'usernum', 'COLUMN';


Eski sütunda herhangi bir kısıtlamanız varsa, bu kadar basit değil.
Suncat2000

13

Aşağıdaki komut dosyası, 'Kimlik' adlı bir sütun için Kimlik alanını kaldırır

Umarım yardımcı olur.

BEGIN TRAN
BEGIN TRY
    EXEC sp_rename '[SomeTable].[Id]', 'OldId';

    ALTER TABLE [SomeTable] ADD Id int NULL

    EXEC ('UPDATE [SomeTable] SET Id = OldId')

    ALTER TABLE [SomeTable] NOCHECK CONSTRAINT ALL

    ALTER TABLE [SomeTable] DROP CONSTRAINT [PK_constraintName];
    ALTER TABLE [SomeTable] DROP COLUMN OldId
    ALTER TABLE [SomeTable] ALTER COLUMN [Id] INTEGER NOT NULL
    ALTER TABLE [SomeTable] ADD CONSTRAINT PK_JobInfo PRIMARY KEY (Id)

    ALTER TABLE [SomeTable] CHECK CONSTRAINT ALL

    COMMIT TRAN
END TRY
BEGIN CATCH
    ROLLBACK TRAN   
    SELECT ERROR_MESSAGE ()
END CATCH

4

Kimlik sütun adını bilmediğimizde , körük kodu iyi çalışıyor .

Verileri yeni geçici tabloya kopyalamanız gerekiyor Invoice_DELETED. ve bir dahaki sefere kullanıyoruz:

insert into Invoice_DELETED select * from Invoice where ...


SELECT t1.*
INTO Invoice_DELETED
FROM Invoice t1
LEFT JOIN Invoice ON 1 = 0
--WHERE t1.InvoiceID = @InvoiceID

Daha fazla açıklama için bkz .: https://dba.stackexchange.com/a/138345/101038


1
YAAAAAAAAAA'yı SEVİYORUM. Tam olarak aradığım şey, bir "SELECT * INTO" dan "KİMLİK" oluşturmaktan kaçınmanın kolay bir yolu (ihtiyaç duyan yedeklemeler için yeni bir tablo geçici oluşturmak için)
KurzedMetal

küçük ve güzel;)
Zolfaghari

3
ALTER TABLE tablename add newcolumn int
update tablename set newcolumn=existingcolumnname
ALTER TABLE tablename DROP COLUMN existingcolumnname;
EXEC sp_RENAME 'tablename.oldcolumn' , 'newcolumnname', 'COLUMN'

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


1

Sadece benimle aynı sorunu yaşayan biri için. Sadece bir kez eklemek istiyorsanız, bunun gibi bir şey yapabilirsiniz.

Diyelim ki iki sütunlu bir tablonuz var

ID Identity (1,1) | Name Varchar

ve ID = 4 olan bir satır eklemek istersiniz. Yani 3'e yeniden aktarırsınız, böylece bir sonraki 4 olur

DBCC CHECKIDENT([YourTable], RESEED, 3)

Ekleme Yap

INSERT  INTO [YourTable]
        ( Name )
VALUES  ( 'Client' )

Ve tohumunuzu en yüksek kimliğe geri getirin, varsayalım 15

DBCC CHECKIDENT([YourTable], RESEED, 15)

Bitti!


1

Ben de aynı gereksinime sahiptim ve bu şekilde deneyebilirsiniz, kişisel olarak size tavsiye ederim, lütfen tablonuzu manuel olarak tasarlayın ve betiği oluşturun ve aşağıda yaptığım şey eski tabloyu yeniden adlandırmak ve ayrıca yedekleme için kısıtlamaktı.

/* To prevent any potential data loss issues, you should review this script in detail before running it outside the context of the database designer.*/
BEGIN TRANSACTION

SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
ALTER TABLE dbo.SI_Provider_Profile
    DROP CONSTRAINT DF_SI_Provider_Profile_SIdtDateTimeStamp
GO
ALTER TABLE dbo.SI_Provider_Profile
    DROP CONSTRAINT DF_SI_Provider_Profile_SIbHotelPreLoaded
GO
CREATE TABLE dbo.Tmp_SI_Provider_Profile
    (
    SI_lProvider_Profile_ID int NOT NULL,
    SI_lSerko_Integrator_Token_ID int NOT NULL,
    SI_sSerko_Integrator_Provider varchar(50) NOT NULL,
    SI_sSerko_Integrator_Profile varchar(50) NOT NULL,
    SI_dtDate_Time_Stamp datetime NOT NULL,
    SI_lProvider_ID int NULL,
    SI_sDisplay_Name varchar(10) NULL,
    SI_lPurchased_From int NULL,
    SI_sProvider_UniqueID varchar(255) NULL,
    SI_bHotel_Pre_Loaded bit NOT NULL,
    SI_sSiteName varchar(255) NULL
    )  ON [PRIMARY]
GO
ALTER TABLE dbo.Tmp_SI_Provider_Profile SET (LOCK_ESCALATION = TABLE)
GO
ALTER TABLE dbo.Tmp_SI_Provider_Profile ADD CONSTRAINT
    DF_SI_Provider_Profile_SIdtDateTimeStamp DEFAULT (getdate()) FOR SI_dtDate_Time_Stamp
GO
ALTER TABLE dbo.Tmp_SI_Provider_Profile ADD CONSTRAINT
    DF_SI_Provider_Profile_SIbHotelPreLoaded DEFAULT ((0)) FOR SI_bHotel_Pre_Loaded
GO
IF EXISTS(SELECT * FROM dbo.SI_Provider_Profile)
        EXEC('INSERT INTO dbo.Tmp_SI_Provider_Profile (SI_lProvider_Profile_ID, SI_lSerko_Integrator_Token_ID, SI_sSerko_Integrator_Provider, SI_sSerko_Integrator_Profile, SI_dtDate_Time_Stamp, SI_lProvider_ID, SI_sDisplay_Name, SI_lPurchased_From, SI_sProvider_UniqueID, SI_bHotel_Pre_Loaded, SI_sSiteName)
        SELECT SI_lProvider_Profile_ID, SI_lSerko_Integrator_Token_ID, SI_sSerko_Integrator_Provider, SI_sSerko_Integrator_Profile, SI_dtDate_Time_Stamp, SI_lProvider_ID, SI_sDisplay_Name, SI_lPurchased_From, SI_sProvider_UniqueID, SI_bHotel_Pre_Loaded, SI_sSiteName FROM dbo.SI_Provider_Profile WITH (HOLDLOCK TABLOCKX)')
GO

-- Rename the primary key constraint or unique key In SQL Server constraints such as primary keys or foreign keys are objects in their own right, even though they are dependent upon the "containing" table.
EXEC sp_rename 'dbo.SI_Provider_Profile.PK_SI_Provider_Profile', 'PK_SI_Provider_Profile_Old';
GO
-- backup old table in case of 
EXECUTE sp_rename N'dbo.SI_Provider_Profile', N'SI_Provider_Profile_Old', 'OBJECT'
GO

EXECUTE sp_rename N'dbo.Tmp_SI_Provider_Profile', N'SI_Provider_Profile', 'OBJECT'
GO

ALTER TABLE dbo.SI_Provider_Profile ADD CONSTRAINT
    PK_SI_Provider_Profile PRIMARY KEY NONCLUSTERED 
    (
    SI_lProvider_Profile_ID
    ) WITH( PAD_INDEX = OFF, FILLFACTOR = 90, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

GO
COMMIT TRANSACTION

1

SQL Server'da kimlik eklemeyi şu şekilde açıp kapatabilirsiniz:

IDENTITY_INSERT table_name AÇIK AYARLA

- sorgularınızı burada çalıştırın

IDENTITY_INSERT table_name OFF AYARLA

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.