Xóa danh tính khỏi một cột trong bảng


127

Chúng tôi có một bảng 5 GB (gần 500 triệu hàng) và chúng tôi muốn xóa thuộc tính nhận dạng trên một trong các cột, nhưng khi chúng tôi cố gắng thực hiện điều này thông qua SSMS - nó đã hết thời gian.

Điều này có thể được thực hiện thông qua T-SQL không?


1
Bạn có thể gửi lược đồ của bảng ở đây?
Al W

Tôi chắc chắn có những lý do tuyệt vời mà SQL Server không hỗ trợ xóa thuộc tính nhận dạng khỏi cột thông qua câu lệnh ALTER TABLE ... đơn giản, nhưng hiện tại nó vẫn làm tôi buồn vì đó là trường hợp.
Jon Schneider

Câu trả lời:


143

Bạn không thể xóa IDENTITYthông số kỹ thuật một khi được đặt.

Để xóa toàn bộ cột:

ALTER TABLE yourTable
DROP COLUMN yourCOlumn;

Thông tin về ALTER TABLE tại đây

Nếu bạn cần giữ dữ liệu, nhưng xóa IDENTITYcột, bạn sẽ cần:

  • Tạo một cột mới
  • Chuyển dữ liệu từ IDENTITYcột hiện có sang cột mới
  • Thả IDENTITYcột hiện có .
  • Đổi tên cột mới thành tên cột ban đầu

3
bạn có thể xóa thông số nhận dạng. Trong thực tế, tôi đã phải làm điều đó ngày hôm qua bằng cách sử dụng SSMS mặc dù không phải trên 500 triệu hàng.
Simon

33
@simon nếu bạn loại bỏ các thay đổi của mình, bạn sẽ thấy SSMS thực sự đang tạo một bản sao của bảng với thuộc tính nhận dạng.
Code Magician

3
Tôi chỉ muốn thêm để đổi tên cột mới thành tên của cột ban đầu. Ngoài ra, nếu identitycột này được sử dụng như một phần của foreign keybảng khác, trước tiên bạn sẽ phải loại bỏ các ràng buộc, sau đó thực hiện hành động như @AdamWenger đã đề cập về việc xóa danh tính attribute/property.. Bạn cũng có thể xem liên kết này để biết thêm chi tiết về việc chỉ xóa thuộc tính: blog.sqlauthority.com/2009/05/03/ trên .. Chúc may mắn!
Nonym

1
Đối với người đã bỏ phiếu - tôi sẽ đánh giá cao những gì bạn không thích về câu trả lời của tôi.
Adam Wenger

1
Hãy xem câu trả lời của Mark Sowul dưới đây. Giảm nhu cầu di chuyển dữ liệu từ cột này sang cột khác. Sử dụng câu trả lời của Mark, bạn chỉ xáo trộn siêu dữ liệu. Không có vấn đề lớn trừ khi bạn đang làm việc trên một bảng có hàng chục hoặc hàng trăm triệu hàng. Câu trả lời của Mark Mark ngăn chặn việc di chuyển cột trong lược đồ bảng. Tôi chỉ thử nó và nó hoạt động như một bùa mê. Rất thông minh.
Andrew Steitz

100

Nếu bạn muốn làm điều này mà không cần thêm và điền vào một cột mới , không sắp xếp lại các cộtgần như không có thời gian chết vì không có dữ liệu nào thay đổi trên bảng, hãy thực hiện một số phép thuật với chức năng phân vùng (nhưng vì không có phân vùng nào được sử dụng nên bạn không ' t cần phiên bản doanh nghiệp):

  1. Xóa tất cả các khóa ngoại trỏ đến bảng này
  2. Kịch bản bảng được tạo; đổi tên mọi thứ, ví dụ 'MyTable2', 'MyIndex2', v.v. Xóa đặc tả IDENTITY.
  3. Bây giờ bạn sẽ có hai bảng "giống hệt nhau", một bảng đầy đủ, một bảng trống khác không có SẮC.
  4. Chạy ALTER TABLE [Original] SWITCH TO [Original2]
  5. Bây giờ bảng gốc của bạn sẽ trống và bảng mới sẽ có dữ liệu. Bạn đã chuyển siêu dữ liệu cho hai bảng (tức thì).
  6. Bỏ bản gốc (bảng bây giờ trống), exec sys.sp_renameđể đổi tên các đối tượng lược đồ khác nhau thành tên gốc và sau đó bạn có thể tạo lại các khóa ngoại của mình.

Ví dụ: đã cho:

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

Bạn có thể làm như sau:

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

Tôi không có thời gian để thực sự thử điều này, nhưng thật tốt khi biết lần sau tôi thực sự cần phải bỏ một danh tính.
CoderDennis

11
Đây phải là câu trả lời được chấp nhận. Đó là cách thực sự duy nhất để xóa một cột danh tính mà không cần di chuyển dữ liệu lớn.
Vaccano

Ồ Điều này rất thông minh.
Andrew Steitz

Câu trả lời này là phi thường! Cảm ơn!
Jon

5
Nếu sử dụng SQL Management Studio để tạo kịch bản bảng, hãy đảm bảo bật Công cụ> Tùy chọn> SQL Server Object Explorer> Scripting> Tùy chọn bảng và xem> Chỉ mục tập lệnh (Sai ​​theo mặc định)
user423430

61

Điều này trở nên lộn xộn với các ràng buộc khóa chính và nước ngoài, vì vậy đây là một số tập lệnh để giúp bạn theo cách của mình:

Đầu tiên, tạo một cột trùng lặp với một tên tạm thời:

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

Tiếp theo, lấy tên của ràng buộc khóa chính của bạn:

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

Bây giờ hãy thử thả ràng buộc khóa chính cho cột của bạn:

ALTER TABLE yourTable DROP CONSTRAINT PK_yourTable_id;

Nếu bạn có khóa ngoại, nó sẽ thất bại, vì vậy nếu bỏ các ràng buộc khóa ngoại. GIỮ TRACK THEO BẢNG MÀ BẠN CHẠY NÀY CHO VẬY BẠN CÓ THỂ THÊM CÁC CONSTRAINTS TRỞ LẠI SAU !!!

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

Khi tất cả các ràng buộc khóa ngoại của bạn đã được xóa, bạn sẽ có thể xóa ràng buộc PK, bỏ cột đó, đổi tên cột tạm thời của bạn và thêm ràng buộc PK vào cột đó:

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;

Cuối cùng, thêm các ràng buộc FK trở lại:

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

El Fin!


chú ý đến phiên bản máy chủ sql của bạn, tôi đã thử trong máy chủ azure sql, không phải tất cả các hoạt động ở đây đều được hỗ trợ trong phiên bản azure azure.
dasons

Cảm ơn câu trả lời! Đã giúp tôi rất nhiều! Bạn chỉ nên thêm một xác minh cho các chỉ mục tham chiếu cột. Một cái gì đó như: 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

Thủ thuật tốt, đã giúp tôi rất nhiều, Nhưng có một điểm, tôi muốn đề cập ở đây là, Khi chúng tôi thêm một cột trùng lặp mới như đã đề cập ở bước 1, nó đã thêm vào cuối nhưng nói chung chúng tôi muốn rằng cột khóa chính của chúng tôi tức là Id cột 1 trong bảng đó. Vì vậy, có bất kỳ giải pháp cho điều đó?
Ashish Shukla

19

Tôi chỉ có vấn đề tương tự. 4 câu lệnh trong SSMS thay vì sử dụng GUI và nó rất nhanh.

  • Tạo một cột mới

    alter table users add newusernum int;

  • Sao chép giá trị qua

    update users set newusernum=usernum;

  • Thả cột cũ

    alter table users drop column usernum;

  • Đổi tên cột mới thành tên cột cũ

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


Sẽ không đơn giản nếu bạn có bất kỳ ràng buộc nào trên cột cũ.
Suncat2000

13

Tập lệnh sau sẽ xóa trường Danh tính cho một cột có tên 'Id'

Hy vọng nó giúp.

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

Mã dưới đây hoạt động tốt, khi chúng ta không biết tên cột nhận dạng .

Cần sao chép dữ liệu vào bảng tạm thời mới như thế nào Invoice_DELETED. và lần sau chúng tôi sử dụng:

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

Để biết thêm giải thích, xem: https://dba.stackexchange.com/a/138345/101038


1
YÊU YAAAAAAAAAA. Chính xác những gì tôi đang tìm kiếm, một cách dễ dàng để tránh tạo ra "IDENTITY" từ "CHỌN * VÀO" (để tạo một temp bảng mới cho các bản sao lưu cần thiết)
KurzingMetal

nó nhỏ và đẹp;)
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'

Tuy nhiên, mã trên chỉ hoạt động nếu không có quan hệ khóa chính-ngoại


1

Chỉ cần cho một người có cùng một vấn đề tôi đã làm. Nếu bạn chỉ muốn thực hiện một số chèn chỉ một lần bạn có thể làm một cái gì đó như thế này.

Giả sử bạn có một bảng có hai cột

ID Identity (1,1) | Name Varchar

và muốn chèn một hàng có ID = 4. Vì vậy, bạn đã đổi nó thành 3 để hàng tiếp theo là 4

DBCC CHECKIDENT([YourTable], RESEED, 3)

Thực hiện Chèn

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

Và lấy hạt giống của bạn trở lại ID cao nhất, giả sử là 15

DBCC CHECKIDENT([YourTable], RESEED, 15)

Làm xong!


1

Tôi có cùng một yêu cầu và bạn có thể thử theo cách này, cá nhân tôi khuyên bạn, vui lòng thiết kế thủ công bảng của bạn và tạo tập lệnh, và những gì tôi đã làm dưới đây là đổi tên bảng cũ và ràng buộc của nó để sao lưu.

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

Trong SQL Server, bạn có thể bật và tắt nhận dạng chèn như thế này:

THIẾT LẬP IDENTITY_INSERT tên_bảng

- chạy truy vấn của bạn ở đây

SET IDENTITY_INSERT bảng_name TẮT

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.