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 IDENTITY
cột và (2) đảm bảo rằng IDENTITY
bắ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 IDENTITY
cộ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_temp
và đặt cột đó thành các id
giá 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ỏ id
cột hiện có (bạn không thể "thêm" một IDENTITY
cộ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_INSERT
trê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 IDENTITY
cộ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 đó, DELETE
tất cả các hàng trong bảng, nhưng các hàng bạn đang xóa đều nằm OUTPUT
trong cùng một bảng - nhưng có các giá trị cụ thể cho id
cộ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_INSERT
tắ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 IDENTITY
cột, vì vậy bản ghi tiếp theo id
sẽ tiếp tục sau số hiện có cao nhất trong id
cộ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ụ, id
số 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 TRANSACTION
vì 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 .. INTO
sẽ 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 id
cộ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ỳ INSERT
và DELETE
kí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
id
cột là một IDENTITY
,
- Đặt
IDENTITY_INSERT ON
cho bảng,
- Đặt bàn
- Đặt
IDENTITY_INSERT OFF
và
- Thay đổi danh tính.
IDENTITY
sao