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


160

ฉันมี 2005 ฐานข้อมูล MS SQL กับตารางกับคอลัมน์Test เป็นคอลัมน์ข้อมูลประจำตัวIDID

ฉันมีแถวในตารางนี้และทุกคนมีค่าที่เพิ่มขึ้นของ ID อัตโนมัติที่สอดคล้องกัน

ตอนนี้ฉันต้องการเปลี่ยน ID ทุกตัวในตารางนี้ดังนี้:

ID = ID + 1

แต่เมื่อฉันทำสิ่งนี้ฉันได้รับข้อผิดพลาด:

ไม่สามารถอัปเดตคอลัมน์ข้อมูลประจำตัว 'ID'

ฉันเคยลองแล้ว:

    ALTER TABLE Test NOCHECK CONSTRAINT ALL 
    set identity_insert ID ON

แต่นี่ไม่ได้แก้ปัญหา

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

คำตอบ:


220

คุณจำเป็นต้อง

set identity_insert YourTable ON

จากนั้นลบแถวของคุณและแทรกใหม่ด้วยข้อมูลประจำตัวอื่น

เมื่อคุณเสร็จสิ้นการแทรกอย่าลืมปิด identity_insert

set identity_insert YourTable OFF

133
การตั้งค่านี้จะทำงานเมื่อใส่ข้อมูลเท่านั้นและไม่สามารถอัปเดตได้ คำสั่ง UPDATE จะยังคงล้มเหลว
Husein Roncevic

31
สำหรับการอัปเดตคุณต้องลบและแทรกใหม่ ไม่มีวิธีอื่น
ashes999

1
@Martin ด้วยวิธีการแก้ปัญหาของคุณดูเหมือนยาวเกินไป ความสามารถในการทำได้สองขั้นตอน (การปิดตัวตนลบ / แทรกตัวตนบน) นั้นมีประสิทธิภาพมากกว่า
ashes999

3
@ ashes999 นั่นคือ 4 ขั้นตอนไม่ใช่ 2 คำตอบของฉันคืออีกหนึ่ง (สร้างตารางสวิตช์อัปเดตเปลี่ยนกลับลดลง) มันน่าจะเป็นที่คุณคุ้นเคยกับขั้นตอนเหล่านี้มากขึ้นเพื่อให้พวกเขาดูซับซ้อนน้อยลง การอัปเดตอาจมีประสิทธิภาพมากขึ้นแล้วลบการแทรกเมื่อมีหลายแถวที่เกี่ยวข้อง นอกจากนี้คุณอยู่ที่ไหนแถวที่ถูกลบถือ? หาก#tempตารางที่คุณวางเป็นขั้นตอนอื่นคุณยังไม่ได้นับที่นี่
Martin Smith

40

IDENTITY ค่าคอลัมน์ไม่เปลี่ยนรูป

อย่างไรก็ตามคุณสามารถสลับข้อมูลเมตาของตารางเพื่อลบIDENTITYคุณสมบัติทำการอัปเดตจากนั้นสลับกลับ

สมมติว่าโครงสร้างดังต่อไปนี้

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'

จากนั้นคุณสามารถทำได้

/*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*/

ใน SQL Server 2012 เป็นไปได้ที่จะมีคอลัมน์การเพิ่มอัตโนมัติที่สามารถอัปเดตได้ง่ายขึ้นด้วย 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
ลื่นมาก เรียนรู้สิ่งใหม่ทุกวัน (BTW ฉันทดสอบสิ่งนี้ใน SQLExpress แม้ว่าจะมีสวิตช์ที่ไม่ได้ใช้การแบ่งพาร์ติชัน แต่อย่างใด) โปรดทราบว่าตารางจะต้องตรงกับที่ค่อนข้างสวย (ดัชนี
FK

1
วิธีเปลี่ยนใช้งานได้เมื่อคุณมี PK, FKs, ดัชนีและมุมมองที่สร้างบนตารางดั้งเดิมหรือไม่ พวกเขาจะแตกโดยใช้วิธีนี้หรือไม่?
tj

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

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

26

ผ่าน UI ในตัวจัดการ SQL Server 2005 เปลี่ยนคอลัมน์ลบคุณสมบัติ autonumber (identity) ของคอลัมน์ (เลือกตารางโดยคลิกขวาที่มันแล้วเลือก "ออกแบบ")

จากนั้นเรียกใช้แบบสอบถามของคุณ:

UPDATE table SET Id = Id + 1

จากนั้นไปและเพิ่มคุณสมบัติ autonumber กลับไปที่คอลัมน์


3
หากคุณทำการเปลี่ยนแปลงด้วยตนเองคุณสามารถขอให้ผู้จัดการสร้างสคริปต์ SQL สำหรับการเปลี่ยนแปลง (เมนูตัวออกแบบตารางสร้างสคริปต์การเปลี่ยนแปลง) สำหรับการเปลี่ยนแปลงนี้จะสร้างตารางใหม่และคัดลอกข้อมูลข้ามจากนั้นลบต้นฉบับ
Robin Bennett

2
@tomaszs - ตัวอย่างรหัสที่มีประสิทธิภาพมากขึ้นเนื่องจากไม่ได้สร้างตารางขึ้นใหม่เลย (นี่จะทำสองครั้ง) อยู่ในคำตอบสุดท้ายของฉันที่นี่
Martin Smith

คุณไม่สามารถเพิ่มข้อมูลประจำตัวกลับ คุณ stackoverflow.com/questions/1049210/…
Tomas Kubes

ขอบคุณ มันสมบูรณ์แบบ ผมมี 1 แถวในตารางของฉันที่ฉันไม่ได้ตระหนักถึงดังนั้นสคริปต์บูตของฉันสำหรับตารางของฉันมีIdค่ารถยนต์ประจำตัวออกโดย 1
พระอิศวร

18

ประการแรกการตั้งค่าเปิดหรือปิด IDENTITY_INSERT สำหรับเรื่องนั้นจะไม่ทำงานสำหรับสิ่งที่คุณต้องการ (ใช้สำหรับแทรกค่าใหม่เช่นการเสียบช่องว่าง)

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


9

สามารถทำได้โดยใช้ตารางชั่วคราว

ความคิด

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

แบบสอบถาม SQL

สมมติว่าtestตารางของคุณมีสองคอลัมน์เพิ่มเติม ( column2และcolumn3) และมี 2 ตารางที่มีคีย์ต่างประเทศที่อ้างถึงtestเรียกforeign_table1และforeign_table2(เนื่องจากปัญหาในชีวิตจริงนั้นไม่เคยง่ายเลย)

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;

แค่นั้นแหละ.


6

DBCC CHECKIDENT ('databasename.dbo.orders', RESEED, 999) คุณสามารถเปลี่ยนหมายเลขคอลัมน์ข้อมูลประจำตัวด้วยคำสั่งนี้และคุณสามารถเริ่มหมายเลขฟิลด์นั้นจากทุกหมายเลขที่คุณต้องการตัวอย่างเช่นในคำสั่งของฉันฉันขอให้เริ่มจาก 1,000 (999 + 1) หวังว่ามันจะเพียงพอ ... ขอให้โชคดี


4

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

อยากรู้ว่าทำไมคุณถึงต้องทำสิ่งนี้ ... ส่วนใหญ่ที่ฉันเคยทำกับคอลัมน์ Identity คือการใส่ตัวเลขและฉันเพิ่งใช้ DBEC CHECKIDENT (tablename RESEED newnextnumber)

โชคดี!


1

การแก้ไขข้อมูลประจำตัวอาจล้มเหลวขึ้นอยู่กับปัจจัยหลายประการโดยส่วนใหญ่จะหมุนรอบวัตถุ / ความสัมพันธ์ที่เชื่อมโยงกับคอลัมน์ id ดูเหมือนว่าการออกแบบฐานข้อมูลจะเป็นปัญหาที่นี่เช่นเดียวกับ id ของแทบจะไม่เคยเปลี่ยนแปลงหาก (ฉันแน่ใจว่าคุณมีเหตุผลของคุณและจะเปลี่ยนการเปลี่ยนแปลง) หากคุณต้องการเปลี่ยน id เป็นครั้งคราวฉันขอแนะนำให้สร้างคอลัมน์ dummy id ใหม่ที่ไม่ใช่คีย์ / autonumber หลักที่คุณสามารถจัดการตัวเองและสร้างจากค่าปัจจุบัน อีกวิธีหนึ่งความคิดของ Chrisotphers ข้างต้นจะเป็นคำแนะนำอื่น ๆ ของฉันหากคุณมีปัญหากับการอนุญาตให้ใส่ข้อมูลประจำตัว

โชคดี

ป.ล. มันไม่ได้ล้มเหลวเพราะลำดับที่กำลังทำงานอยู่กำลังพยายามอัปเดตค่าในรายการไปยังรายการที่มีอยู่แล้วในรายการรหัส คลัตช์ที่ straws อาจเพิ่มจำนวนแถว + 1 จากนั้นถ้ามันทำงานลบจำนวนแถว: -S


1

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


1

คุณสามารถแทรกแถวใหม่ด้วยค่าที่แก้ไขแล้วลบแถวเก่า ตัวอย่างต่อไปนี้เปลี่ยน ID ให้เหมือนกับ foreign key 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

ขั้นแรกให้บันทึก ID ทั้งหมดและแก้ไขโดยทางโปรแกรมเป็นค่าที่คุณไม่ต้องการจากนั้นลบออกจากฐานข้อมูลแล้วใส่รหัสอีกครั้งโดยใช้สิ่งที่คล้ายกัน:

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

สำหรับการใช้เม็ดมีดจำนวนมาก:

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

ข้อมูลตัวอย่างจาก file.csv:

2;
3;
4;
5;
6;

หากคุณไม่ได้ตั้งค่าidentity_insertเป็นปิดคุณจะได้รับข้อผิดพลาดต่อไปนี้:

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


0

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

  1. ลบคอลัมน์ที่แทรกผิด
  2. ใช้การแทรกแบบบังคับโดยใช้การเปิด / ปิดแบบระบุตัวตน

http://beyondrelational.com/modules/2/blogs/28/posts/10337/sql-server-how-do-i-insert-an-explicit-value-into-an-identity-column-how-do- I-ปรับปรุงที่คุ้มค่าของ an.aspx


1
ไม่แน่ใจว่าคุณตอบคำถามที่นี่จริง ๆ
Andrew Barber

0

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

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

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

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