Cách tôi hiểu câu hỏi của bạn là bạn có một bảng hiện có với một cột cho đến nay đã được điền với các giá trị thủ công và bây giờ bạn muốn (1) biến cột này thành một IDENTITYcột và (2) đảm bảo rằng IDENTITYbắt đầu từ giá trị gần đây nhất trong các hàng hiện có.
Trước hết, một số dữ liệu thử nghiệm để chơi với:
CREATE TABLE dbo.ident_test (
id int NOT NULL,
xyz varchar(10) NOT NULL,
CONSTRAINT PK_ident_test PRIMARY KEY CLUSTERED (id)
);
INSERT INTO dbo.ident_test (id, xyz)
VALUES (1, 'test'),
(2, 'test'),
(5, 'test'),
(6, 'test'),
(10, 'test'),
(18, 'test'),
(19, 'test'),
(20, 'test');
Mục tiêu là tạo cột khóa chính của bảng id, một IDENTITYcột sẽ bắt đầu từ 21 cho bản ghi tiếp theo được chèn. Trong ví dụ này, cột xyzđại diện cho tất cả các cột khác của bảng.
Trước khi bạn làm bất cứ điều gì, xin vui lòng đọc các cảnh báo ở dưới cùng của bài viết này.
Trước hết, trong trường hợp có lỗi xảy ra:
BEGIN TRANSACTION;
Bây giờ, hãy thêm một cột công việc tạm thời id_tempvà đặt cột đó thành các idgiá trị của cột hiện có :
ALTER TABLE dbo.ident_test ADD id_temp int NULL;
UPDATE dbo.ident_test SET id_temp=id;
Tiếp theo, chúng ta cần bỏ idcột hiện có (bạn không thể "thêm" một IDENTITYcột vào cột hiện có, bạn phải tạo cột dưới dạng một IDENTITY). Khóa chính cũng phải đi, vì cột phụ thuộc vào nó.
ALTER TABLE dbo.ident_test DROP CONSTRAINT PK_ident_test;
ALTER TABLE dbo.ident_test DROP COLUMN id;
... và thêm cột một lần nữa, lần này là một IDENTITY, cùng với khóa chính:
ALTER TABLE dbo.ident_test ADD id int IDENTITY(1, 1) NOT NULL;
ALTER TABLE dbo.ident_test ADD CONSTRAINT PK_ident_test PRIMARY KEY CLUSTERED (id);
Đây là nơi nó trở nên thú vị. Bạn có thể bật IDENTITY_INSERTtrên bảng, điều đó có nghĩa là bạn có thể xác định thủ công các giá trị của IDENTITYcột khi bạn chèn các hàng mới (mặc dù không cập nhật các hàng hiện có).
SET IDENTITY_INSERT dbo.ident_test ON;
Với tập hợp đó, DELETEtất cả các hàng trong bảng, nhưng các hàng bạn đang xóa đều nằm OUTPUTtrong cùng một bảng - nhưng có các giá trị cụ thể cho idcột (từ cột dự phòng).
DELETE FROM dbo.ident_test
OUTPUT deleted.id_temp AS id, deleted.xyz
INTO dbo.ident_test (id, xyz);
Một lần, xong, IDENTITY_INSERTtắt lại.
SET IDENTITY_INSERT dbo.ident_test OFF;
Bỏ cột tạm thời mà chúng tôi đã thêm:
ALTER TABLE dbo.ident_test DROP COLUMN id_temp;
Và cuối cùng, đã định lại IDENTITYcột, vì vậy bản ghi tiếp theo idsẽ tiếp tục sau số hiện có cao nhất trong idcột:
DECLARE @maxid int;
SELECT @maxid=MAX(id) FROM dbo.ident_test;
DBCC CHECKIDENT ("dbo.ident_test", RESEED, @maxid)
Kiểm tra bảng ví dụ, idsố cao nhất là 20.
SELECT * FROM dbo.ident_test;
Thêm một hàng khác và kiểm tra mới của nó IDENTITY:
INSERT INTO dbo.ident_test (xyz) VALUES ('New row');
SELECT * FROM dbo.ident_test;
Trong ví dụ, hàng mới sẽ có id=21. Cuối cùng, nếu bạn hài lòng, hãy thực hiện giao dịch:
COMMIT TRANSACTION;
Quan trọng
Đây không phải là một hoạt động tầm thường, và nó mang theo khá nhiều rủi ro mà bạn nên biết.
Làm điều này trong một môi trường thử nghiệm chuyên dụng. Có bản sao lưu. :)
Tôi thích sử dụng BEGIN/COMMIT TRANSACTIONvì nó ngăn các quá trình khác làm hỏng bảng trong khi bạn đang thay đổi nó và nó cho bạn khả năng khôi phục lại mọi thứ nếu có sự cố. Tuy nhiên, bất kỳ quy trình nào khác cố gắng truy cập vào bảng của bạn trước khi bạn cam kết giao dịch của mình sẽ phải chờ. Điều này có thể khá tệ nếu bạn có một bàn lớn và / hoặc bạn đang ở trong môi trường sản xuất.
OUTPUT .. INTOsẽ không hoạt động nếu bảng mục tiêu của bạn có các ràng buộc khóa ngoại hoặc bất kỳ tính năng nào khác mà tôi không thể nhớ ra khỏi đỉnh đầu. Thay vào đó, bạn có thể tải dữ liệu vào một bảng tạm thời, sau đó chèn lại vào bảng gốc. Bạn có thể sử dụng chuyển đổi phân vùng (ngay cả khi bạn không sử dụng phân vùng).
Chạy các câu lệnh này từng cái một, không phải theo lô hoặc trong một thủ tục được lưu trữ.
Hãy thử nghĩ về những thứ khác có thể phụ thuộc vào idcột mà bạn đang thả và tạo lại. Bất kỳ chỉ mục nào cũng sẽ phải được loại bỏ và tạo lại (giống như chúng ta đã làm với khóa chính). Hãy nhớ kịch bản mọi chỉ mục và ràng buộc mà bạn sẽ cần phải tạo lại trước đó.
Vô hiệu hóa bất kỳ INSERTvà DELETEkích hoạt trên bảng.
Nếu tạo lại bảng là một tùy chọn:
Nếu việc tạo lại bảng là một tùy chọn cho bạn, mọi thứ sẽ đơn giản hơn rất nhiều:
- Tạo bảng trống, với
idcột là một IDENTITY,
- Đặt
IDENTITY_INSERT ONcho bảng,
- Đặt bàn
- Đặt
IDENTITY_INSERT OFFvà
- Thay đổi danh tính.
IDENTITYsao