ค่าที่ชัดเจนสำหรับคอลัมน์ข้อมูลประจำตัวในตารางสามารถระบุได้เฉพาะเมื่อมีการใช้รายการคอลัมน์และ IDENTITY_INSERT อยู่บน SQL Server


187

ฉันพยายามที่จะทำแบบสอบถามนี้

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

แต่หลังจากฉันวิ่ง

set identity_insert dbo.tbl_A_archive on

ฉันได้รับข้อความแสดงข้อผิดพลาดนี้

ค่าที่ชัดเจนสำหรับคอลัมน์ข้อมูลประจำตัวในตาราง 'dbo.tbl_A_archive' สามารถระบุได้เฉพาะเมื่อใช้รายการคอลัมน์และ IDENTITY_INSERT เปิดอยู่

tbl_Aเป็นตารางขนาดใหญ่ในแถวและความกว้างนั่นคือมีคอลัมน์จำนวนมาก ฉันไม่ต้องการพิมพ์คอลัมน์ทั้งหมดด้วยตนเอง ฉันจะทำให้เรื่องนี้ทำงานได้อย่างไร


ฉันได้ติดตั้งเซิร์ฟเวอร์ที่เชื่อมโยงแล้ว!
jhowe

4
ฉันมีปัญหานี้เช่นกันยกเว้น "การแทรกลงใน X select * Y" ก็ไม่มีปัญหาจนกว่าฉันจะเปลี่ยน schema ของตาราง
FistOfFury

คำตอบ:


81

สรุป

SQL Server จะไม่ยอมให้คุณใส่ค่าที่ชัดเจนในคอลัมน์ข้อมูลประจำตัวเว้นแต่ว่าคุณจะใช้รายการคอลัมน์ ดังนั้นคุณมีตัวเลือกต่อไปนี้:

  1. ทำรายการคอลัมน์ (ด้วยตนเองหรือใช้เครื่องมือดูด้านล่าง)

หรือ

  1. สร้างคอลัมน์ข้อมูลประจำตัวในคอลัมน์tbl_A_archiveปกติและไม่ใช่ข้อมูลประจำตัว : หากตารางของคุณเป็นตารางเก็บถาวรและคุณระบุค่าที่ชัดเจนสำหรับคอลัมน์ข้อมูลประจำตัวทำไมคุณถึงต้องมีคอลัมน์ข้อมูลประจำตัวด้วย เพียงใช้ int ปกติแทน

รายละเอียดเกี่ยวกับโซลูชันที่ 1

แทน

SET IDENTITY_INSERT archive_table ON;

INSERT INTO archive_table
  SELECT *
  FROM source_table;

SET IDENTITY_INSERT archive_table OFF;

คุณต้องเขียน

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, ...ที่มีชื่อของคอลัมน์ทั้งหมดในตารางของคุณ หากคุณต้องการสร้างรายการคอลัมน์นั้นโดยอัตโนมัติให้ดูที่คำตอบของเดฟหรือคำตอบของแอนโดมาร์


รายละเอียดเกี่ยวกับโซลูชัน 2

น่าเสียดายที่เป็นไปไม่ได้ที่จะ "เปลี่ยนประเภท" ของคอลัมน์ข้อมูลเฉพาะตัวเป็นคอลัมน์ไม่ใช่ข้อมูลประจำตัว โดยทั่วไปคุณมีตัวเลือกดังต่อไปนี้:

  • หากตารางเก็บถาวรยังไม่มีข้อมูลให้วางคอลัมน์และเพิ่มตารางใหม่โดยไม่มีข้อมูลระบุตัวตน

หรือ

  • ใช้ SQL Server Studio จัดการการตั้งค่าIdentity Specification/ ทรัพย์สินของคอลัมน์ประจำในตารางเก็บของคุณไป(Is Identity) Noเบื้องหลังฉากนี้จะสร้างสคริปต์เพื่อสร้างตารางและคัดลอกข้อมูลที่มีอยู่ดังนั้นจะทำอย่างไรที่คุณจะยังต้องล้างTools/ Options/ Designers/ /Table and Database DesignersPrevent saving changes that require table re-creation

หรือ


1
ไปยังโซลูชันด้านล่างของคุณ: หากคอลัมน์มี "ตัวตน (1, 1)" หรืออะไรทำนองนี้เขาจะต้องลบออกชั่วคราวเช่นกัน
Aleksandr Khomenko

1
@AleksandrKhomenko: ใช่ว่าเป็นสิ่งที่ฉันหมายโดย"ทำให้ [มัน] ปกติ ( ที่ไม่ใช่ตัวตน ) int คอลัมน์"
Heinzi

1
ขอโทษสำหรับความสับสน. ฉันตั้งใจจริงว่าเขาจะต้องลบคุณสมบัติการเพิ่มอัตโนมัติเช่นกัน ในกรณีของ SQL-Server มันเรียกว่า "ตัวตน (1, 1)" - คำตอบของคุณถูกต้องอย่างแน่นอน แต่ MySQL และ Oracle มีคำสั่งอื่นสำหรับมัน (และมันไม่ชัดเจนโปรดดูที่w3schools.com/sql/sql_autoincrement.asp )
Aleksandr Khomenko

2
รายละเอียดนี้ไม่เพียงพอ ฉันเข้าใจว่ามันอาจถูกท่องไปบ้าง แต่มันไร้สาระกับคนอื่น
ดีเจ

1
@DJ .: ฉันได้เพิ่มรายละเอียดบางอย่าง
Heinzi

332
SET IDENTITY_INSERT tableA ON

คุณต้องสร้างรายการคอลัมน์สำหรับคำสั่ง INSERT ของคุณ:

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

ไม่ชอบ "INSERT Into tableA SELECT ........ "

SET IDENTITY_INSERT tableA OFF

17
+1 ... คุณต้องการเพียงคอลัมน์ที่ชัดเจนในส่วนคำสั่ง SELECT ของแบบสอบถาม คุณสามารถเก็บเครื่องหมายดอกจันไว้ในส่วนคำสั่ง INSERT ได้
MacGyver

8
... เว้นเสียแต่ว่าเป้าหมายจะมีคอลัมน์ข้อมูลประจำตัวและตารางต้นฉบับไม่มีคอลัมน์ข้อมูลระบุตัวตน
MacGyver

1
คำตอบนี้ชัดเจนกว่า Heinzi เล็กน้อยเนื่องจากมันกล่าวถึง SET IDENTITY_INSERT
Marty

4
+1 ใช้งานได้อย่างมีเสน่ห์! อย่างไรก็ตาม "คุณสามารถเก็บเครื่องหมายดอกจันในส่วนคำสั่ง INSERT ของข้อความค้นหา" จะไม่ทำงานที่นี่
Shai Alon

1
ฉันได้รับข้อผิดพลาดนี้เมื่อคอลัมน์ในส่วนคำสั่งที่เลือกไม่ตรงกับตารางปลายทาง เพื่อให้แน่ใจว่าสิ่งนี้แทรกใช้งานได้สำหรับฉัน
Jose

39

หากคุณใช้ SQL Server Management Studio คุณไม่จำเป็นต้องพิมพ์รายการคอลัมน์ด้วยตัวเองเพียงคลิกขวาที่ตารางในObject Explorerและเลือกตารางสคริปต์เป็น -> SELECT ไปที่ -> หน้าต่างตัวแก้ไขคิวรีใหม่

หากคุณไม่ได้เป็นเช่นนั้นแบบสอบถามที่คล้ายกันนี้จะช่วยเป็นจุดเริ่มต้น:

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
สิ่งนี้สามารถเลือกให้เป็นตัวแปรและใช้ในแบบสอบถาม SQL แบบไดนามิก คุณบันทึกวันของฉัน ขอบคุณมาก!
Pawel Cioch

1
ขอบคุณ! ฉันทำสิ่งนี้กับมันgist.github.com/timabell/0ddd6a69565593f907c7
Tim Abell

ว้าว. ฉันหมดหวังที่จะมองหาสิ่งนี้เพื่อสร้างแบบสอบถามของฉันแบบไดนามิก แปลกใจที่เห็นสิ่งนี้ที่นี่ ขอบคุณเพื่อน
Yasin Bilir

24

เห็นด้วยกับคำตอบของ Heinzi สำหรับตัวเลือกที่สองแรกนี่คือแบบสอบถามที่สร้างรายการคอลัมน์ที่คั่นด้วยเครื่องหมายจุลภาคในตาราง:

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

สำหรับตารางขนาดใหญ่สามารถบันทึกงานพิมพ์จำนวนมากได้ :)


@ ขอบคุณเป็นประโยชน์จริงๆ :)
Chirag Thakar

บางครั้งคุณเพียงแค่ต้องการวิธีแก้ปัญหาอย่างจริงจัง ขอบคุณ!
Tobias Feil

15

หากตาราง "เก็บถาวร" มีความหมายว่าเป็นสำเนาหลักของตารางหลักของคุณฉันขอแนะนำให้คุณลบข้อเท็จจริงที่ว่า id เป็นคอลัมน์ระบุ ด้วยวิธีนี้มันจะช่วยให้คุณใส่พวกเขา

อีกทางหนึ่งคุณสามารถอนุญาตและไม่อนุญาตให้มีการระบุตัวตนของตารางด้วยคำสั่งต่อไปนี้

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

สุดท้ายหากคุณต้องการคอลัมน์ข้อมูลประจำตัวเพื่อให้ทำงานเหมือนเดิมคุณก็สามารถเรียกใช้ proc ที่จัดเก็บไว้ได้เสมอ

sp_columns tbl_A_archive 

สิ่งนี้จะคืนค่าคอลัมน์ทั้งหมดจากตารางซึ่งคุณสามารถตัดและวางลงในคิวรีของคุณ (นี่เกือบจะดีกว่าการใช้ *)


11

สำหรับคำสั่ง SQL คุณต้องระบุรายการคอลัมน์ สำหรับเช่น

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

แทน

INSERT INTO tbl VALUES ( value1,value2)

2
นี่ไม่ใช่กรณีของคำสั่ง OP ค่าไม่จำเป็นต้องใช้ถ้า INSERT INTO ถูกตามด้วยคำสั่ง SELECT โปรดแก้ไขหรือลบคำตอบของคุณ
แกรี่

4

ทั้งสองจะทำงานได้ แต่ถ้าคุณยังคงได้รับข้อผิดพลาดโดยใช้ # 1 ไปที่ # 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
นี่ไม่ใช่วิธีที่จะไปได้ถ้า OP กำลังแทรกหลาย ๆ ระเบียน คุณไม่สนใจ "tbl_A เป็นตารางขนาดใหญ่ในแถวและความกว้างนั่นคือมีคอลัมน์จำนวนมากฉันไม่ต้องการพิมพ์คอลัมน์ทั้งหมดด้วยตนเอง"
แกรี่

4

เพื่อเติมชื่อคอลัมน์ทั้งหมดลงในรายการที่คั่นด้วยจุลภาคสำหรับคำสั่ง Select สำหรับการแก้ปัญหาที่กล่าวถึงสำหรับคำถามนี้ฉันใช้ตัวเลือกต่อไปนี้เนื่องจากมีความละเอียดน้อยกว่าคำตอบส่วนใหญ่ที่นี่ อย่างไรก็ตามคำตอบส่วนใหญ่ที่นี่ยังคงเป็นที่ยอมรับอย่างสมบูรณ์อย่างไรก็ตาม

1)

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

2)นี่อาจเป็นวิธีที่ง่ายที่สุดในการสร้างคอลัมน์หากคุณมี SQL Server SSMS

1) ไปที่ตารางใน Object Explorer และคลิกที่ + ทางด้านซ้ายของชื่อตารางหรือดับเบิลคลิกที่ชื่อตารางเพื่อเปิดรายการย่อย

2) ลากโฟลเดอร์ย่อยของคอลัมน์ไปยังพื้นที่แบบสอบถามหลักและมันจะทำการค้นหารายชื่อคอลัมน์ทั้งหมดโดยอัตโนมัติ


3

คุณต้องระบุชื่อคอลัมน์ที่คุณต้องการแทรกหากมีคอลัมน์ข้อมูลประจำตัว ดังนั้นคำสั่งจะเป็นดังนี้:

SET IDENTITY_INSERT DuplicateTable ON

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

SET IDENTITY_INSERT DuplicateTable OFF

หากตารางของคุณมีหลายคอลัมน์ให้เรียกชื่อคอลัมน์เหล่านั้นโดยใช้คำสั่งนี้

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

(หลังจากลบเครื่องหมายจุลภาคสุดท้าย (',')) เพียงคัดลอกชื่อคอลัมน์ที่ผ่านมา


3

สิ่งนี้น่าจะใช้ได้ ฉันเพิ่งพบปัญหาของคุณ:

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;

น่าเสียดายที่ดูเหมือนว่าคุณต้องการรายการของคอลัมน์รวมถึงคอลัมน์ข้อมูลประจำตัวเพื่อแทรกระเบียนที่ระบุตัวตน อย่างไรก็ตามคุณไม่จำเป็นต้องแสดงรายการคอลัมน์ใน SELECT ในฐานะ@Dave Cluderayแนะนำสิ่งนี้จะส่งผลให้มีรายการที่จัดรูปแบบแล้วสำหรับคุณในการคัดลอกและวาง (หากน้อยกว่า 200,000 ตัวอักษร)

ฉันเพิ่ม USE เนื่องจากฉันสลับระหว่างอินสแตนซ์

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

ไม่เหมือน

INSERT INTO tableA
SELECT * FROM tableB

SET IDENTITY_INSERT tableA OFF

2

ข้อมูลโค้ดนี้แสดงวิธีแทรกลงในตารางเมื่อคอลัมน์คีย์หลักของข้อมูลประจำตัวเปิด

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

สำหรับถ้าคุณต้องการที่จะแทรกค่าของคุณจากตารางหนึ่งไปยังอีกผ่านกระบวนการที่เก็บไว้ ฉันใช้สิ่งนี้และนี่อันหลังซึ่งเกือบจะเหมือนคำตอบของ 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

มีหนึ่งคอลัมน์ขึ้นไปที่มีคุณสมบัติการเพิ่มอัตโนมัติหรือค่าของแอตทริบิวต์นั้นจะถูกคำนวณเป็นข้อ จำกัด คุณกำลังพยายามแก้ไขคอลัมน์นั้น

มีสองวิธีในการแก้ไข 1) พูดถึงคอลัมน์อื่น ๆ อย่างชัดเจนและตั้งค่าของพวกเขาเท่านั้นและ PrimaryKey หรือค่าคอลัมน์ที่เพิ่มขึ้นอัตโนมัติจะตั้งค่าโดยอัตโนมัติ

2) คุณสามารถเปิด INDENTITY_INSERT จากนั้นเรียกใช้คิวรีแทรกของคุณในที่สุดก็ปิด IDENTITY_INSERT

คำแนะนำ: ทำตามขั้นตอนแรกเพราะเป็นวิธีที่เหมาะสมและมีประสิทธิภาพมากขึ้น

สำหรับข้อมูลเพิ่มเติมอ่านบทความนี้ใน SQL


0

โปรดตรวจสอบให้แน่ใจว่าชื่อคอลัมน์ชนิดข้อมูลและคำสั่งซื้อในตารางที่คุณเลือกระเบียนเหมือนกับที่อยู่ในตารางปลายทาง ความแตกต่างเพียงอย่างเดียวควรเป็นตารางปลายทางนั้นมีคอลัมน์ข้อมูลประจำตัวเป็นคอลัมน์แรกที่ไม่ได้อยู่ในตารางต้นฉบับ

ฉันประสบปัญหาคล้ายกันเมื่อฉันเรียกใช้งาน "INSERT INTO table_Dest SELECT * จาก table_source_linked_server_excel" ตารางมี 115 คอลัมน์

ฉันมีสองตารางดังกล่าวที่ฉันโหลดข้อมูลจาก Excel (เป็นเซิร์ฟเวอร์ที่เชื่อมโยง) ลงในตารางในฐานข้อมูล ในตารางฐานข้อมูลฉันได้เพิ่มคอลัมน์ข้อมูลประจำตัวที่เรียกว่า 'id' ซึ่งไม่มีอยู่ใน Excel ต้นฉบับ สำหรับหนึ่งตารางแบบสอบถามทำงานได้สำเร็จและอีกฉันได้รับข้อผิดพลาด "ค่าที่ชัดเจนสำหรับคอลัมน์ข้อมูลเฉพาะในตารางสามารถระบุได้เฉพาะเมื่อมีการใช้รายการคอลัมน์และ IDENTITY_INSERT อยู่บน SQL Server" นี่ทำให้งงเพราะสถานการณ์เดียวกันทั้งแบบสอบถาม ดังนั้นฉันจึงตรวจสอบเรื่องนี้และสิ่งที่ฉันพบคือในแบบสอบถามที่ฉันได้รับข้อผิดพลาดกับ INSERT INTO .. ​​SELECT *:

  1. ชื่อคอลัมน์บางส่วนในตารางต้นฉบับถูกแก้ไข แต่ค่านั้นถูกต้อง
  2. มีบางคอลัมน์เพิ่มเติมนอกเหนือจากคอลัมน์ข้อมูลจริงที่เลือกโดย SELECT * ฉันค้นพบสิ่งนี้โดยใช้ตัวเลือกของ "ตารางสคริปต์เป็น> เลือกเพื่อ> หน้าต่างแบบสอบถามใหม่" บนตาราง Excel ต้นฉบับ (ใต้เซิร์ฟเวอร์ที่เชื่อมโยง) มีหนึ่งคอลัมน์ที่ซ่อนอยู่หลังคอลัมน์สุดท้ายใน Excel แม้ว่าจะไม่มีข้อมูลใด ๆ ฉันลบคอลัมน์นั้นในตาราง Excel ต้นฉบับและบันทึกไว้

หลังจากทำการเปลี่ยนแปลงสองข้อด้านบนแล้วแบบสอบถามสำหรับ INSERT INTO ... SELECT * ก็ประสบความสำเร็จ คอลัมน์ข้อมูลประจำตัวในตารางปลายทางสร้างค่าข้อมูลประจำตัวสำหรับแต่ละแถวที่แทรกตามที่คาดไว้

ดังนั้นแม้ว่าตารางปลายทางอาจมีคอลัมน์ข้อมูลประจำตัวที่ไม่ได้อยู่ในตารางต้นฉบับ INSERT INTO .. ​​SELECT * จะทำงานได้สำเร็จหากชื่อประเภทข้อมูลและลำดับคอลัมน์ในแหล่งที่มาและปลายทางเหมือนกันทุกประการ

หวังว่าจะช่วยใครซักคน


-1

ฉันคิดว่าข้อผิดพลาดนี้เกิดขึ้นเนื่องจากไม่ตรงกับจำนวนคอลัมน์ในคำจำกัดความของตารางและจำนวนของคอลัมน์ในคิวรีแทรก นอกจากนี้ความยาวของคอลัมน์จะถูกตัดออกด้วยค่าที่ป้อน ดังนั้นเพียงตรวจทานคำจำกัดความของตารางเพื่อแก้ไขปัญหานี้


ใช้งานได้สำหรับฉัน: ฉันลืมเพิ่มคอลัมน์ลงในตารางจากการออกแบบสิ่งที่ดีในการตรวจสอบนี้ก่อนที่จะลองคำตอบอื่น ๆ
Exel Gamboa
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.