Làm thế nào để thay đổi giá trị cột danh tính theo chương trình?


160

Tôi có một cơ sở dữ liệu MS SQL 2005 với một bảng Testcó cột ID. IDlà một cột danh tính.

Tôi có các hàng trong bảng này và tất cả chúng đều có giá trị tăng tự động ID tương ứng.

Bây giờ tôi muốn thay đổi mọi ID trong bảng này như sau:

ID = ID + 1

Nhưng khi tôi làm điều này, tôi gặp một lỗi:

Không thể cập nhật cột nhận dạng 'ID'.

Tôi đã thử điều này:

    ALTER TABLE Test NOCHECK CONSTRAINT ALL 
    set identity_insert ID ON

Nhưng điều này không giải quyết được vấn đề.

Tôi cần phải đặt danh tính cho cột này, nhưng tôi cũng cần thay đổi giá trị theo thời gian. Vì vậy, câu hỏi của tôi là làm thế nào để hoàn thành nhiệm vụ này.

Câu trả lời:


220

Bạn cần phải

set identity_insert YourTable ON

Sau đó xóa hàng của bạn và đặt lại nó với danh tính khác nhau.

Khi bạn đã thực hiện thao tác chèn, đừng quên tắt nhận dạng_insert

set identity_insert YourTable OFF

133
cài đặt này sẽ chỉ hoạt động khi chèn dữ liệu chứ không phải khi cập nhật. Tuyên bố CẬP NHẬT vẫn sẽ thất bại.
Husein Roncevic

31
Để cập nhật, bạn cần xóa và chèn lại. Không có cách nào khác.
tro999

1
@MartinSmith giải pháp của bạn có vẻ quá dài. Có thể làm điều đó trong hai bước (tắt nhận dạng, xóa / chèn, nhận dạng) sẽ hiệu quả hơn nhiều.
tro999

3
@ as999999 Đó là 4 bước chứ không phải 2. Câu trả lời của tôi chỉ còn một bước nữa (tạo bảng, chuyển đổi, cập nhật, chuyển đổi lại, thả xuống) Có lẽ bạn đã quen thuộc hơn với các bước này để chúng trông bớt rối mắt hơn. Cập nhật có thể hiệu quả hơn nhiều sau đó xóa chèn khi có nhiều hàng tham gia. Ngoài ra, bạn đang giữ các hàng bị xóa ở đâu? Nếu một #tempbảng mà sau đó bạn thả đó là một bước khác bạn chưa tính ở đây.
Martin Smith

40

IDENTITY giá trị cột là bất biến.

Tuy nhiên, có thể chuyển siêu dữ liệu bảng để xóa thuộc IDENTITYtính, thực hiện cập nhật, sau đó chuyển lại.

Giả sử cấu trúc sau

CREATE TABLE Test
(
ID INT IDENTITY(1,1) PRIMARY KEY,
X VARCHAR(10)
)

INSERT INTO Test 
OUTPUT INSERTED.*
SELECT 'Foo' UNION ALL
SELECT 'Bar' UNION ALL
SELECT 'Baz'

Sau đó bạn có thể làm

/*Define table with same structure but no IDENTITY*/
CREATE TABLE Temp
(
ID INT PRIMARY KEY,
X VARCHAR(10)
)

/*Switch table metadata to new structure*/
ALTER TABLE Test SWITCH TO Temp;

/*Do the update*/
UPDATE Temp SET ID = ID + 1;

/*Switch table metadata back*/
ALTER TABLE Temp SWITCH TO Test;

/*ID values have been updated*/
SELECT *
FROM Test

/*Safety check in case error in preceding step*/
IF NOT EXISTS(SELECT * FROM Temp)
    DROP TABLE Temp /*Drop obsolete table*/

Trong SQL Server 2012, có thể có một cột tăng tự động cũng có thể được cập nhật đơn giản hơn với SEQUENCES

CREATE SEQUENCE Seq
    AS INT
    START WITH 1
    INCREMENT BY 1

CREATE TABLE Test2
(
ID INT DEFAULT NEXT VALUE FOR Seq NOT NULL PRIMARY KEY,
X VARCHAR(10)
)

INSERT INTO Test2(X)
SELECT 'Foo' UNION ALL
SELECT 'Bar' UNION ALL
SELECT 'Baz'

UPDATE Test2 SET ID+=1

1
Rất lắt léo. Tìm hiểu một cái gì đó mới mỗi ngày (BTW Tôi đã thử nghiệm điều này trên SQLE Express; mặc dù SWITCH TO nó không sử dụng phân vùng, rõ ràng). Lưu ý rằng bảng phải khớp chính xác khá nhiều (chỉ mục, FK, v.v.)
Mark Sowul

1
Phương thức chuyển đổi có hoạt động khi bạn có PK, FK, Index và Chế độ xem được xây dựng trên bảng gốc không? Họ sẽ phá vỡ bằng cách sử dụng phương pháp này?
tj

1
@tj khi tạo tập lệnh bảng tạm thời ra bảng nguồn bao gồm tất cả các chỉ mục và các ràng buộc. Sau đó thay đổi tên của bảng và các ràng buộc để tránh va chạm. Lượt xem sẽ không gây ra sự cố trừ khi được lập chỉ mục hoặc lược đồ.
Martin Smith

Không hoạt động nếu có một chỉ mục tìm kiếm toàn văn trên bảng. Tôi cho rằng có thể loại bỏ nó và tạo lại nó sau đó, nhưng tôi đã không thử nghiệm.
youen

26

Thông qua giao diện người dùng trong SQL Server 2005, thay đổi cột loại bỏ thuộc tính autonumber (danh tính) của cột (chọn bảng bằng cách nhấp chuột phải vào nó và chọn "Thiết kế").

Sau đó chạy truy vấn của bạn:

UPDATE table SET Id = Id + 1

Sau đó đi và thêm thuộc tính autonumber trở lại cột.


3
Nếu bạn thực hiện thay đổi theo cách thủ công, bạn có thể yêu cầu người quản lý tạo tập lệnh SQL để thay đổi (trình đơn trình thiết kế bảng, tạo tập lệnh thay đổi). Đối với thay đổi này, nó tạo một bảng mới và sao chép dữ liệu qua, sau đó xóa bản gốc.
Robin Bennett

2
@tomaszs - Một ví dụ mã cũng hiệu quả hơn vì nó hoàn toàn không xây dựng lại bảng (điều này sẽ làm như vậy hai lần) nằm trong câu trả lời muộn của tôi ở đây
Martin Smith

Bạn không thể thêm danh tính trở lại. Phải không stackoverflow.com/questions/1049210/
Mạnh

Cảm ơn. Điều này là hoàn hảo. Tôi có 1 hàng trong bảng mà tôi không biết, vì vậy các tập lệnh bootstrap cho bảng của tôi đã Idtắt các giá trị Tự động nhận dạng bằng 1.
Shiva

18

Đầu tiên, cài đặt IDENTITY_INSERT bật hoặc tắt cho vấn đề đó sẽ không hoạt động cho những gì bạn yêu cầu (nó được sử dụng để chèn các giá trị mới, chẳng hạn như cắm các khoảng trống).

Thực hiện thao tác thông qua GUI chỉ tạo một bảng tạm thời, sao chép tất cả dữ liệu qua một bảng mới mà không có trường nhận dạng và đổi tên bảng.


9

Điều này có thể được thực hiện bằng cách sử dụng một bảng tạm thời.

Ý tưởng

  • vô hiệu hóa các ràng buộc (trong trường hợp id của bạn được tham chiếu bởi khóa ngoại)
  • tạo bảng tạm thời với id mới
  • xóa nội dung bảng
  • sao chép lại dữ liệu từ bảng đã sao chép vào bảng gốc của bạn
  • cho phép các ràng buộc bị vô hiệu hóa trước

Truy vấn SQL

Giả sử testbảng của bạn có hai cột bổ sung ( column2column3) và có 2 bảng có khóa ngoại tham chiếu testđược gọi foreign_table1foreign_table2(vì các vấn đề thực tế không bao giờ đơn giản).

alter table test nocheck constraint all;
alter table foreign_table1 nocheck constraint all;
alter table foreign_table2 nocheck constraint all;
set identity_insert test on;

select id + 1 as id, column2, column3 into test_copy from test v;
delete from test;
insert into test(id, column2, column3)
select id, column2, column3 from test_copy

alter table test check constraint all;
alter table foreign_table1 check constraint all;
alter table foreign_table2 check constraint all;
set identity_insert test off;
drop table test_copy;

Đó là nó.


6

DBCC CHECKIDENT ('databasename.dbo.nings', RESEED, 999) bạn có thể thay đổi bất kỳ số cột nhận dạng nào bằng lệnh này và bạn cũng có thể bắt đầu số trường đó từ mọi số bạn muốn. Ví dụ trong lệnh của tôi, tôi yêu cầu bắt đầu từ 1000 (999 + 1) hy vọng rằng nó sẽ đủ ... chúc may mắn


4

Nếu cột không phải là PK, bạn luôn có thể tạo cột MỚI trong bảng với các số tăng dần, bỏ bản gốc và sau đó thay đổi cột mới thành cũ.

tò mò về lý do tại sao bạn có thể cần phải làm điều này ... hầu hết tôi từng phải sử dụng các cột Nhận dạng là để lấp đầy các số và tôi đã kết thúc bằng cách sử dụng DBCC CHECKIDENT (tablename, RESEED, newnextnumber)

chúc may mắn!


1

Sửa đổi danh tính có thể thất bại tùy thuộc vào một số yếu tố, chủ yếu xoay quanh các đối tượng / mối quan hệ được liên kết với cột id. Có vẻ như thiết kế db là vấn đề ở đây vì id hiếm khi thay đổi (tôi chắc chắn rằng bạn có lý do của mình và đang thay đổi các thay đổi). Thỉnh thoảng, nếu bạn thực sự cần thay đổi id, tôi khuyên bạn nên tạo một cột id giả mới không phải là khóa chính / số tự động mà bạn có thể tự quản lý và tạo từ các giá trị hiện tại. Thay phiên, ý tưởng của Chrisotphers ở trên sẽ là đề xuất khác của tôi nếu bạn gặp vấn đề với việc cho phép chèn danh tính.

Chúc may mắn

PS không thất bại vì thứ tự tuần tự mà nó đang chạy đang cố cập nhật một giá trị trong danh sách thành một mục đã tồn tại trong danh sách id? bám vào ống hút, có thể thêm số lượng hàng + 1, sau đó nếu nó hoạt động trừ đi số lượng hàng: -S


1

Nếu thỉnh thoảng bạn cần thay đổi ID, tốt nhất không nên sử dụng cột nhận dạng. Trước đây, chúng tôi đã triển khai các trường số tự động theo cách thủ công bằng cách sử dụng bảng 'Bộ đếm' theo dõi ID tiếp theo cho mỗi bảng. IIRC chúng tôi đã làm điều này vì các cột danh tính đã gây ra lỗi cơ sở dữ liệu trong SQL2000 nhưng việc có thể thay đổi ID đôi khi rất hữu ích để thử nghiệm.


1

Bạn có thể chèn các hàng mới với các giá trị được sửa đổi và sau đó xóa các hàng cũ. Ví dụ sau thay đổi ID giống với khóa ngoài PersonId

SET IDENTITY_INSERT [PersonApiLogin] ON

INSERT INTO [PersonApiLogin](
       [Id]
      ,[PersonId]
      ,[ApiId]
      ,[Hash]
      ,[Password]
      ,[SoftwareKey]
      ,[LoggedIn]
      ,[LastAccess])
SELECT [PersonId]
      ,[PersonId]
      ,[ApiId]
      ,[Hash]
      ,[Password]
      ,[SoftwareKey]
      ,[LoggedIn]
      ,[LastAccess]
FROM [db304].[dbo].[PersonApiLogin]
GO

DELETE FROM [PersonApiLogin]
WHERE [PersonId] <> ID
GO
SET IDENTITY_INSERT [PersonApiLogin] OFF
GO

1

Trước tiên, lưu tất cả ID và thay đổi chúng theo chương trình thành các giá trị bạn không có, sau đó xóa chúng khỏi cơ sở dữ liệu và sau đó chèn lại chúng bằng cách sử dụng một cái gì đó tương tự:

use [Name.Database]
go
set identity_insert [Test] ON
insert into [dbo].[Test]
           ([Id])
     VALUES
           (2)
set identity_insert [Test] OFF

Để sử dụng chèn số lượng lớn:

use [Name.Database]
go
set identity_insert [Test] ON
BULK INSERT [Test]
FROM 'C:\Users\Oscar\file.csv'
WITH (FIELDTERMINATOR = ';',
      ROWTERMINATOR = '\n',
      KEEPIDENTITY)
set identity_insert [Test] OFF

Dữ liệu mẫu từ file.csv:

2;
3;
4;
5;
6;

Nếu bạn không identity_inserttắt, bạn sẽ gặp lỗi sau:

Không thể chèn giá trị rõ ràng cho cột nhận dạng trong bảng 'Kiểm tra' khi IDENTITY_INSERT được đặt thành TẮT.


0

Tôi đã thấy một bài viết hay giúp tôi vào phút cuối .. Tôi đang cố gắng chèn một vài hàng vào một bảng có cột nhận dạng nhưng đã làm sai và phải xóa lại. Khi tôi xóa các hàng thì cột nhận dạng của tôi đã thay đổi. Tôi đã cố gắng tìm cách cập nhật cột được chèn nhưng - không may mắn. Vì vậy, trong khi tìm kiếm trên google đã tìm thấy một liên kết ..

  1. Đã xóa các cột bị chèn sai
  2. Sử dụng lực chèn bằng cách sử dụng bật / tắt nhận dạng (giải thích bên dưới)

http://beyondrelational.com/modules/2/bloss/28/posts/10337/sql-server-how-do-i-insert-an-explicit-value-into-an-identity-column-how-do- i-update-the-value-of-an.aspx


1
Tuy nhiên, không chắc chắn bạn đã thực sự trả lời câu hỏi ở đây.
Andrew Barber

0

Câu hỏi rất hay, đầu tiên chúng ta cần vào IDENTITY_INSERT cho bảng cụ thể, sau đó chạy truy vấn chèn (Phải chỉ định tên cột).

Lưu ý: Sau khi chỉnh sửa cột danh tính, đừng quên tắt IDENTITY_INSERT. Nếu bạn không thực hiện, bạn không thể Chỉnh sửa cột nhận dạng cho bất kỳ bảng nào khác.

SET IDENTITY_INSERT Emp_tb_gb_Menu ON
     INSERT Emp_tb_gb_Menu(MenuID) VALUES (68)
SET IDENTITY_INSERT Emp_tb_gb_Menu OFF

http://allinworld99.blogspot.com/2016/07/how-to-edit-identity-field-in-sql.html

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.