Giá trị rõ ràng cho cột danh tính trong bảng chỉ có thể được chỉ định khi danh sách cột được sử dụng và IDENTITY_INSERT ở trên máy chủ SQL


187

Tôi đang cố gắng thực hiện truy vấn này

INSERT INTO dbo.tbl_A_archive
  SELECT *
  FROM SERVER0031.DB.dbo.tbl_A

nhưng ngay cả sau khi tôi chạy

set identity_insert dbo.tbl_A_archive on

Tôi nhận được thông báo lỗi này

Giá trị rõ ràng cho cột danh tính trong bảng 'dbo.tbl_A_archive' chỉ có thể được chỉ định khi danh sách cột được sử dụng và IDENTITY_INSERT được BẬT.

tbl_Alà một bảng lớn theo hàng và chiều rộng, tức là nó có RẤT NHIỀU cột. Tôi không muốn phải gõ tất cả các cột theo cách thủ công. Làm thế nào tôi có thể làm điều này để làm việc?


Tôi đã thiết lập một máy chủ được liên kết bằng cách này!
jhowe

4
Tôi cũng đang gặp vấn đề này, ngoại trừ "chèn vào X chọn * Y" không phải là vấn đề cho đến khi tôi thay đổi lược đồ bảng
FistOfFury

Câu trả lời:


78

Tóm lược

SQL Server sẽ không cho phép bạn chèn một giá trị rõ ràng vào cột nhận dạng trừ khi bạn sử dụng danh sách cột. Vì vậy, bạn có các tùy chọn sau:

  1. Tạo một danh sách cột (bằng tay hoặc sử dụng các công cụ, xem bên dưới)

HOẶC LÀ

  1. làm cho cột danh tính tbl_A_archivemột cách thường xuyên, không nhận dạng : Nếu bảng của bạn là bảng lưu trữ và bạn luôn chỉ định giá trị rõ ràng cho cột danh tính, tại sao bạn thậm chí cần một cột định danh? Chỉ cần sử dụng một int thông thường thay thế.

Chi tiết về Giải pháp 1

Thay vì

SET IDENTITY_INSERT archive_table ON;

INSERT INTO archive_table
  SELECT *
  FROM source_table;

SET IDENTITY_INSERT archive_table OFF;

bạn cần viết

SET IDENTITY_INSERT archive_table ON;

INSERT INTO archive_table (field1, field2, ...)
  SELECT field1, field2, ...
  FROM source_table;

SET IDENTITY_INSERT archive_table OFF;

field1, field2, ...chứa tên của tất cả các cột trong bảng của bạn. Nếu bạn muốn tự động tạo danh sách các cột đó, hãy xem câu trả lời của Dave hoặc câu trả lời của Andomar .


Chi tiết về Giải pháp 2

Thật không may, không thể chỉ "thay đổi loại" của một cột int nhận dạng thành một cột int không nhận dạng. Về cơ bản, bạn có các tùy chọn sau:

  • Nếu bảng lưu trữ chưa chứa dữ liệu, hãy thả cột và thêm một cột mới mà không có danh tính.

HOẶC LÀ

  • Sử dụng SQL Server Management Studio để đặt Identity Specification/ (Is Identity)thuộc tính của cột danh tính trong bảng lưu trữ của bạn thành No. Đằng sau hậu trường, điều này sẽ tạo ra một kịch bản để tạo lại bảng và sao chép dữ liệu hiện có, vì vậy, để làm điều đó, bạn cũng sẽ cần hủy đặt Tools/ Options/ Designers/ Table and Database Designers/Prevent saving changes that require table re-creation .

HOẶC LÀ


1
Để giải pháp dưới cùng của bạn: Nếu cột có "IDENTITY (1, 1)" hoặc một cái gì đó như thế này, anh ta cũng sẽ cần phải xóa nó tạm thời.
Alexanderr Khomenko

1
@AleksandrKhomenko: Vâng, đó là những gì tôi muốn nói là "biến [nó] thành một cột int thông thường ( không nhận dạng )" .
Heinzi

1
Xin lỗi vì sự nhầm lẫn. Tôi thực sự có nghĩa là anh ta cũng sẽ cần phải loại bỏ thuộc tính tăng tự động . Trong trường hợp SQL-Server, nó gọi là "IDENTITY (1, 1)" - câu trả lời của bạn là hoàn toàn đúng. Nhưng MySQL và Oracle có một lệnh khác cho nó (và nó trở nên không rõ ràng, vui lòng xem w3schools.com/sql/sql_autoincrement.asp )
Aleksandr Khomenko

2
Điều này là thiếu chi tiết. Tôi hiểu nó có thể là vơ vét đối với một số người nhưng nó vô nghĩa với những người khác
DJ.

1
@DJ.: Tôi đã thêm một số chi tiết.
Heinzi

332
SET IDENTITY_INSERT tableA ON

Bạn phải tạo một danh sách cột cho câu lệnh INSERT của bạn:

INSERT Into tableA ([id], [c2], [c3], [c4], [c5] ) 
SELECT [id], [c2], [c3], [c4], [c5] FROM tableB

không thích "XÁC NHẬN vào bảngA CHỌN ........"

SET IDENTITY_INSERT tableA OFF

17
+1 ... Bạn chỉ cần các cột rõ ràng trong mệnh đề SELECT của truy vấn. Bạn có thể giữ dấu hoa thị trong mệnh đề INSERT của truy vấn
MacGyver

8
... Trừ khi mục tiêu có cột nhận dạng và bảng nguồn không có cột nhận dạng
MacGyver

1
câu trả lời này rõ ràng hơn một chút so với Heinzi vì nó đề cập đến SET IDENTITY_INSERT
Marty

4
+1 Hoạt động như một cơ duyên! Tuy nhiên, "Bạn có thể giữ dấu hoa thị trong mệnh đề INSERT của truy vấn" sẽ không hoạt động ở đây.
Shai Alon

1
Tôi đã gặp lỗi này khi các cột trong mệnh đề chọn không khớp với bảng đích. Đảm bảo điều này, phần chèn hoạt động với tôi
Jose

39

Nếu bạn đang sử dụng SQL Server Management Studio, bạn không phải tự nhập danh sách cột - chỉ cần nhấp chuột phải vào bảng trong Object Explorer và chọn Bảng Script là -> CHỌN đến -> Cửa sổ Trình soạn thảo truy vấn mới .

Nếu bạn không, thì một truy vấn tương tự như vậy sẽ giúp làm điểm bắt đầu:

SELECT SUBSTRING(
    (SELECT ', ' + QUOTENAME(COLUMN_NAME)
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_NAME = 'tbl_A'
        ORDER BY ORDINAL_POSITION
        FOR XML path('')),
    3,
    200000);

2
Điều này có thể được chọn vào một biến và được sử dụng trong truy vấn SQL động. Bạn đã cứu ngày của tôi. Cảm ơn rất nhiều!
Pawel Cioch

1
cảm ơn! Tôi đã thực hiện điều này với nó gist.github.com/timabell/0ddd6a69565593f907c7
Tim Abell

ồ tôi đã tuyệt vọng tìm kiếm điều này để xây dựng truy vấn của tôi một cách linh hoạt. Ngạc nhiên khi thấy điều này ở đây. Cảm ơn bạn đời.
Yasin Bilir

22

Đồng ý với câu trả lời của Heinzi. Đối với tùy chọn thứ hai đầu tiên, đây là truy vấn tạo danh sách các cột được phân tách bằng dấu phẩy trong bảng:

select name + ', ' as [text()] 
from sys.columns 
where object_id = object_id('YourTable') 
for xml path('')

Đối với các bảng lớn, điều này có thể tiết kiệm rất nhiều công việc gõ :)


@ Cảm ơn, thực sự hữu ích. :)
Chirag Thakar

Đôi khi bạn chỉ cần một giải pháp thực dụng. Cảm ơn bạn!
Tobias Feil

15

Nếu bảng "lưu trữ" có nghĩa là một bản sao chính xác của bảng chính của bạn thì tôi chỉ đề nghị bạn loại bỏ thực tế rằng id là một cột định danh. Bằng cách đó, nó sẽ cho phép bạn chèn chúng.

Ngoài ra, bạn có thể cho phép và không cho phép chèn danh tính cho bảng bằng câu lệnh sau

SET IDENTITY_INSERT tbl_A_archive ON
--Your inserts here
SET IDENTITY_INSERT tbl_A_archive OFF

Cuối cùng, nếu bạn cần cột định danh để hoạt động như hiện tại thì bạn luôn có thể chạy Proc được lưu trữ.

sp_columns tbl_A_archive 

Điều này sẽ trả về cho bạn tất cả các cột từ bảng mà sau đó bạn có thể cắt và dán vào truy vấn của mình. (Điều này gần như LUÔN tốt hơn so với sử dụng *)


11

Đối với câu lệnh SQL, bạn cũng phải xác định danh sách cột. Ví dụ.

INSERT INTO tbl (idcol1,col2) VALUES ( value1,value2)

thay vì

INSERT INTO tbl VALUES ( value1,value2)

2
Đây không phải là trường hợp cho tuyên bố của OP. GIÁ TRỊ không bắt buộc nếu INSERT INTO được theo sau bởi câu lệnh CHỌN. Vui lòng sửa lại hoặc xóa câu trả lời của bạn.
Gary

4

Cả hai sẽ hoạt động nhưng nếu bạn vẫn gặp lỗi bằng cách sử dụng # 1 thì hãy chọn # 2

1)

SET IDENTITY_INSERT customers ON
GO
insert into dbo.tbl_A_archive(id, ...)
SELECT Id, ...
FROM SERVER0031.DB.dbo.tbl_A

2)

SET IDENTITY_INSERT customers ON
GO
insert into dbo.tbl_A_archive(id, ...)
VALUES(@Id,....)

4
Đây thực sự không phải là hướng đi nếu OP đang chèn nhiều bản ghi. Bạn đang bỏ qua "tbl_A là một bảng lớn theo hàng và chiều rộng, tức là nó có RẤT NHIỀU cột. Tôi không muốn phải nhập tất cả các cột theo cách thủ công."
Gary

4

Để điền tất cả các tên cột vào danh sách được phân tách bằng dấu phẩy cho câu lệnh Chọn cho các giải pháp được đề cập cho câu hỏi này, tôi sử dụng các tùy chọn sau vì chúng ít dài dòng hơn hầu hết các câu trả lời ở đây. Mặc dù, hầu hết các phản hồi ở đây vẫn hoàn toàn chấp nhận được, tuy nhiên.

1)

SELECT column_name + ',' 
FROM   information_schema.columns 
WHERE  table_name = 'YourTable'

2) Đây có lẽ là cách tiếp cận đơn giản nhất để tạo cột, nếu bạn có SQL Server SSMS.

1) Chuyển đến bảng trong Object Explorer và nhấp vào + ở bên trái của tên bảng hoặc bấm đúp vào tên bảng để mở danh sách phụ.

2) Kéo thư mục con cột vào khu vực truy vấn chính và nó sẽ tự động điền toàn bộ danh sách cột cho bạn.


3

Bạn phải xác định tên cột mà bạn muốn chèn nếu có cột Danh tính. Vì vậy, lệnh sẽ như thế này dưới đây:

SET IDENTITY_INSERT DuplicateTable ON

INSERT Into DuplicateTable ([IdentityColumn], [Column2], [Column3], [Column4] ) 
SELECT [IdentityColumn], [Column2], [Column3], [Column4] FROM MainTable

SET IDENTITY_INSERT DuplicateTable OFF

Nếu bảng của bạn có nhiều cột thì hãy lấy tên cột đó bằng cách sử dụng lệnh này.

SELECT column_name + ','
FROM   information_schema.columns 
WHERE  table_name = 'TableName'
for xml path('')

(sau khi xóa dấu phẩy cuối cùng (',')) Chỉ cần sao chép tên cột trong quá khứ.


3

Điều này nên làm việc. Tôi vừa gặp vấn đề của bạn:

SET IDENTITY_INSERT dbo.tbl_A_archive ON;
INSERT INTO     dbo.tbl_A_archive (IdColumn,OtherColumn1,OtherColumn2,...)
SELECT  *
FROM        SERVER0031.DB.dbo.tbl_A;
SET IDENTITY_INSERT dbo.tbl_A_archive OFF;

Thật không may, có vẻ như bạn cần một danh sách các cột bao gồm cột định danh để chèn các bản ghi xác định danh tính. Tuy nhiên , bạn KHÔNG NÊN liệt kê các cột trong CHỌN. Như @Dave Cluderay đề xuất, điều này sẽ dẫn đến một danh sách được định dạng để bạn sao chép và dán (nếu dưới 200000 ký tự).

Tôi đã thêm USE vì tôi đang chuyển đổi giữa các phiên bản.

USE PES
SELECT SUBSTRING(
    (SELECT ', ' + QUOTENAME(COLUMN_NAME)
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_NAME = 'Provider'
        ORDER BY ORDINAL_POSITION
        FOR XML path('')),
    3,
    200000);

3
SET IDENTITY_INSERT tableA ON

INSERT Into tableA ([id], [c2], [c3], [c4], [c5] ) 
SELECT [id], [c2], [c3], [c4], [c5] FROM tableB

Không như thế này

INSERT INTO tableA
SELECT * FROM tableB

SET IDENTITY_INSERT tableA OFF

2

Đoạn mã này cho biết cách chèn vào bảng khi cột Chính khóa nhận dạng được BẬT.

SET IDENTITY_INSERT [dbo].[Roles] ON
GO
insert into Roles (Id,Name) values(1,'Admin')
GO
insert into Roles (Id,Name) values(2,'User')
GO
SET IDENTITY_INSERT [dbo].[Roles] OFF
GO

1

Vì nếu bạn muốn chèn giá trị của mình từ bảng này sang bảng khác thông qua thủ tục được lưu trữ. Tôi đã sử dụng cái nàycái này , cái sau gần giống như câu trả lời của Andomar.

CREATE procedure [dbo].[RealTableMergeFromTemp]
    with execute as owner
AS
BEGIN
BEGIN TRANSACTION RealTableDataMerge
SET XACT_ABORT ON

    DECLARE @columnNameList nvarchar(MAX) =
     STUFF((select ',' + a.name
      from sys.all_columns a
      join sys.tables t on a.object_id = t.object_id 
       where t.object_id = object_id('[dbo].[RealTable]') 
    order by a.column_id
    for xml path ('')
    ),1,1,'')

    DECLARE @SQLCMD nvarchar(MAX) =N'INSERT INTO [dbo].[RealTable] (' + @columnNameList + N') SELECT * FROM [#Temp]'

    SET IDENTITY_INSERT [dbo].[RealTable] ON;
    exec(@sqlcmd)
    SET IDENTITY_INSERT [dbo].[RealTable] OFF

COMMIT TRANSACTION RealTableDataMerge
END

GO

0

Có một hoặc nhiều cột có thuộc tính tăng tự động hoặc giá trị của thuộc tính đó sẽ được tính là các ràng buộc. Bạn đang cố gắng sửa đổi cột đó.

Có hai cách để giải quyết nó 1) Đề cập rõ ràng đến các cột khác và chỉ đặt giá trị của chúng và giá trị cột Chính hoặc giá trị tăng tự động sẽ được đặt tự động.

2) Bạn có thể bật INDENTITY_INSERT sau đó thực hiện truy vấn chèn của mình cuối cùng tắt IDENTITY_INSERT.

Gợi ý: Thực hiện theo bước đầu tiên vì đây là cách tiếp cận phù hợp và hiệu quả hơn.

Để biết thêm thông tin đọc bài viết này về SQL-helper .


0

Vui lòng đảm bảo rằng tên cột, kiểu dữ liệu và thứ tự trong bảng từ nơi bạn đang chọn các bản ghi hoàn toàn giống với bảng đích. Chỉ có sự khác biệt là bảng đích có một cột định danh là cột đầu tiên, không có trong bảng nguồn.

Tôi đã phải đối mặt với vấn đề tương tự khi tôi đang thực hiện "INSERT INTO table_Dest CHỌN * TỪ bảng_source_linked_server_excel". Các bảng có 115 cột.

Tôi đã có hai bảng như vậy nơi tôi đang tải dữ liệu từ Excel (Là máy chủ được liên kết) vào các bảng trong cơ sở dữ liệu. Trong các bảng cơ sở dữ liệu, tôi đã thêm một cột định danh gọi là 'id' không có trong Excel nguồn. Đối với một bảng, truy vấn đã chạy thành công và trong một bảng khác tôi đã gặp lỗi "Giá trị rõ ràng cho cột định danh trong bảng chỉ có thể được chỉ định khi danh sách cột được sử dụng và IDENTITY_INSERT ở trên máy chủ SQL". Điều này thật khó hiểu vì kịch bản giống hệt nhau cho cả hai truy vấn. Vì vậy, tôi đã điều tra vấn đề này và điều tôi tìm thấy là trong truy vấn mà tôi gặp lỗi với INSERT INTO .. ​​CHỌN *:

  1. Một số tên cột trong bảng nguồn đã được sửa đổi, mặc dù các giá trị là chính xác
  2. Có một số cột bổ sung ngoài các cột dữ liệu thực tế đang được chọn bởi SELECT *. Tôi đã phát hiện ra điều này bằng cách sử dụng tùy chọn "Bảng script như> Chọn vào> cửa sổ truy vấn mới" trên bảng Excel nguồn (bên dưới các máy chủ được liên kết). Có một cột ẩn ngay sau cột cuối cùng trong Excel, mặc dù nó không có bất kỳ dữ liệu nào. Tôi đã xóa cột đó trong bảng Excel nguồn và lưu nó.

Sau khi thực hiện hai thay đổi ở trên, truy vấn INSERT INTO ... SELECT * đã chạy thành công. Cột danh tính trong bảng đích đã tạo các giá trị nhận dạng cho mỗi hàng được chèn như mong đợi.

Vì vậy, mặc dù bảng đích có thể có cột nhận dạng không có trong bảng nguồn, nhưng CHERTN VÀO .. CHỌN * sẽ chạy thành công nếu tên, kiểu dữ liệu và thứ tự cột trong nguồn và đích giống hệt nhau.

Hy vọng nó sẽ giúp được ai đó.


-1

Tôi nghĩ lỗi này xảy ra do không khớp với số cột trong định nghĩa bảng và số cột trong truy vấn chèn. Ngoài ra chiều dài của cột được bỏ qua với giá trị được nhập. Vì vậy, chỉ cần xem lại định nghĩa bảng để giải quyết vấn đề này


Làm việc cho tôi: Tôi quên thêm một cột vào bảng từ thiết kế, điều tốt để kiểm tra điều này trước khi thử các câu trả lời khác.
Exel Gamboa
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.