จะอัพเดตคอลัมน์ข้อมูลประจำตัวใน SQL Server ได้อย่างไร


196

ฉันมีฐานข้อมูล SQL Server และฉันต้องการเปลี่ยนคอลัมน์ข้อมูลประจำตัวเพราะมันเริ่มต้นด้วยจำนวนมาก10010และมันเกี่ยวข้องกับตารางอื่นตอนนี้ฉันมี 200 ระเบียนและฉันต้องการแก้ไขปัญหานี้ก่อนที่จะเพิ่มระเบียน

วิธีที่ดีที่สุดในการเปลี่ยนหรือรีเซ็ตคอลัมน์นี้คืออะไร

คำตอบ:


270

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

SQL Server ไม่อนุญาตให้อัปเดตคอลัมน์ข้อมูลประจำตัวซึ่งแตกต่างจากที่คุณสามารถทำได้กับคอลัมน์อื่น ๆ ที่มีคำสั่งปรับปรุง

แม้ว่าจะมีทางเลือกบางอย่างเพื่อให้บรรลุความต้องการที่คล้ายกัน

  • เมื่อค่าคอลัมน์ผู้ใช้จำเป็นต้องได้รับการปรับปรุงสำหรับบันทึกใหม่

ใช้DBCC CHECKIDENT ซึ่งตรวจสอบค่าตัวตนปัจจุบันสำหรับตารางและหากจำเป็นให้เปลี่ยนค่าตัวตน

DBCC CHECKIDENT('tableName', RESEED, NEW_RESEED_VALUE)
  • เมื่อจำเป็นต้องอัปเดตค่าคอลัมน์ผู้ใช้อีเมลสำหรับระเบียนที่มีอยู่

ใช้IDENTITY_INSERT ซึ่งอนุญาตให้ใส่ค่าที่ชัดเจนลงในคอลัมน์ข้อมูลประจำตัวของตาราง

SET IDENTITY_INSERT YourTable {ON|OFF}

ตัวอย่าง:

-- Set Identity insert on so that value can be inserted into this column
SET IDENTITY_INSERT YourTable ON
GO
-- Insert the record which you want to update with new value in the identity column
INSERT INTO YourTable(IdentityCol, otherCol) VALUES(13,'myValue')
GO
-- Delete the old row of which you have inserted a copy (above) (make sure about FK's)
DELETE FROM YourTable WHERE ID=3
GO
--Now set the idenetity_insert OFF to back to the previous track
SET IDENTITY_INSERT YourTable OFF

6
DBCC รีเซ็ตระเบียนใหม่ถัดไป แต่สิ่งที่ฉันต้องการตอนนี้เปลี่ยนระเบียนที่มีอยู่
Abdulsalam Elsharif

โปรดยกตัวอย่างได้ไหม
Abdulsalam Elsharif

38
@sachin นี้ไม่ได้อัปเดตตัวตนที่มีอยู่ซึ่งเป็นการแทรกด้วยตนเอง
Phill Greggan

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

17
คำตอบที่ยอมรับนี้ไม่ได้ตอบคำถามซึ่งเป็นวิธีการปรับปรุงคอลัมน์ข้อมูลประจำตัว (เช่นUPDATE YourTable SET IdentityCol = 13 ) SET IDENTITY_INSERT YourTable ONอนุญาตเฉพาะ INSERT ไม่ใช่ UPDATE
Ian Boyd

62

หากมีคำถามของคุณถูกต้องคุณต้องการทำเช่นนั้น

update table
set identity_column_name = some value

ให้ฉันบอกคุณว่ามันไม่ใช่กระบวนการที่ง่ายและไม่แนะนำให้ใช้เพราะอาจมีบางอย่างที่foreign keyเกี่ยวข้อง

แต่นี่คือขั้นตอนที่ต้องทำโปรดนั่งback-upโต๊ะ

ขั้นตอนที่ 1- เลือกมุมมองออกแบบของตาราง

ป้อนคำอธิบายรูปภาพที่นี่

ขั้นตอนที่ 2- ปิดคอลัมน์ข้อมูลประจำตัว

ป้อนคำอธิบายรูปภาพที่นี่

ตอนนี้คุณสามารถใช้updateแบบสอบถาม

ตอนนี้redoขั้นตอนที่ 1 และขั้นตอนที่ 2 และเปิดคอลัมน์ข้อมูลประจำตัว

การอ้างอิง


1
ฉันมีตารางอื่นที่เกี่ยวข้องกับตารางนี้สิ่งที่ฉันไม่สามารถทำได้
Abdulsalam Elsharif

4
ดังนั้นคำสั่งจะไม่แนะนำ :)
Luv

3
@AbdusalamElsherif แต่คุณถามวิธีเปลี่ยนคอลัมน์ข้อมูลประจำตัว
paparazzo

@luv อย่างน้อยคุณตอบคำถามที่ถามแล้ว
Greg Greggan

ฉันใช้ขั้นตอนนี้เพื่อตั้งรหัสในฐานข้อมูลการพัฒนาของฉัน มันจะดีถ้ามีคำสั่งที่ให้ฉันทำมันต่อไป แต่งานนี้
Jeff Davis

56

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

set identity_insert YourTable ON

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

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

set identity_insert YourTable OFF

วิธีนี้ง่ายกว่าและปลอดภัยกว่าการปิด Identity สำหรับคอลัมน์!
ป้องกันหนึ่ง

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

18
--before running this make sure Foreign key constraints have been removed that reference the ID. 

--set table to allow identity to be inserted
SET IDENTITY_INSERT yourTable ON;
GO
--insert everything into a temp table
SELECT * 
INTO #tmpYourTable
FROM yourTable

--clear your table
DELETE FROM yourTable
--insert back all the values with the updated ID column
INSERT INTO yourTable (IDCol, OtherCols)
SELECT ID+1 as updatedID --put any other update logic to the ID here
, OtherCols FROM #tmpYourTable
--drop the temp table
DROP TABLE #tmpYourTable
--put identity back to normal
SET IDENTITY_INSERT yourTable OFF;
GO

1
เพียงแค่เคล็ดลับประสิทธิภาพหากตารางมีขนาดใหญ่มากแทนที่จะทำการลบในตารางให้ตัดทอนตาราง yourTable มันเกิดขึ้นทันที ข้อควรระวังแม้ว่าจะไม่มีการย้อนกลับด้วยการตัดทอนเนื่องจากไม่ได้เข้าสู่ระบบ
kuklei


5

คัดลอกตารางของคุณไปยังตารางใหม่โดยไม่มีคอลัมน์ข้อมูลประจำตัว

    select columns into newtable from yourtable

เพิ่มคอลัมน์ข้อมูลประจำตัวไปยัง newtable ด้วย seed ใหม่และทำให้เป็นคีย์หลัก

    ALTER TABLE tableName ADD id MEDIUMINT NOT NULL AUTO_INCREMENT KEY

3
DBCC CHECKIDENT(table_name, RESEED, value)

table_name = ให้ตารางที่คุณต้องการรีเซ็ตค่า

value = ค่าเริ่มต้นที่จะเป็นศูนย์เพื่อเริ่มคอลัมน์ตัวตนด้วย 1


3
SET IDENTITY_INSERT dbo.TableName ON
INSERT INTO dbo.TableName 
(
    TableId, ColumnName1, ColumnName2, ColumnName3
)
VALUES
(
    TableId_Value, ColumnName1_Value, ColumnName2_Value, ColumnName3_Value
)

SET IDENTITY_INSERT dbo.TableName OFF

เมื่อใช้ Identity_Insert อย่าลืมที่จะรวมชื่อคอลัมน์เพราะ sql จะไม่อนุญาตให้คุณแทรกโดยไม่ต้องระบุ


2

คุณยังสามารถใช้SET IDENTITY INSERTเพื่ออนุญาตให้คุณแทรกค่าลงในคอลัมน์ข้อมูลประจำตัว

ตัวอย่าง:

SET IDENTITY_INSERT dbo.Tool ON
GO

จากนั้นคุณสามารถแทรกลงในคอลัมน์ข้อมูลเฉพาะค่าที่คุณต้องการ


1
ALTER TABLE tablename add newcolumn int
update tablename set newcolumn=existingcolumnname
ALTER TABLE tablename DROP COLUMN existingcolumnname;
EXEC sp_RENAME 'tablename.oldcolumn' , 'newcolumnname', 'COLUMN'
update tablename set newcolumnname=value where condition

อย่างไรก็ตามโค้ดด้านบนใช้ได้เฉพาะในกรณีที่ไม่มีความสัมพันธ์กับคีย์หลักจากต่างประเทศ


1

โซลูชันที่สมบูรณ์แบบสำหรับโปรแกรมเมอร์ C # โดยใช้ตัวสร้างคำสั่ง

ก่อนอื่นคุณต้องรู้ข้อเท็จจริงนี้:

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

ดังนั้นเมื่อรู้สิ่งที่คุณต้องทำคือ ตั้งโปรแกรมคำสั่ง SQL Insert ของคุณเองหรือโปรแกรมที่คุณเป็นเจ้าของเครื่องมือสร้างคำสั่ง insert หรือใช้อันนี้ที่ฉันถูกโปรแกรมสำหรับคุณ รับ DataTable สร้างสคริปต์แทรก SQL:

public static string BuildInsertSQLText ( DataTable table )
{
    StringBuilder sql = new StringBuilder(1000,5000000);
    StringBuilder values = new StringBuilder ( "VALUES (" );
    bool bFirst = true;
    bool bIdentity = false;
    string identityType = null;

    foreach(DataRow myRow in table.Rows) 
    {
        sql.Append( "\r\nINSERT INTO " + table.TableName + " (" );

        foreach ( DataColumn column in table.Columns )
        {
            if ( column.AutoIncrement )
            {
                bIdentity = true;

                switch ( column.DataType.Name )
                {
                    case "Int16":
                        identityType = "smallint";
                        break;
                    case "SByte":
                        identityType = "tinyint";
                        break;
                    case "Int64":
                        identityType = "bigint";
                        break;
                    case "Decimal":
                        identityType = "decimal";
                        break;
                    default:
                        identityType = "int";
                        break;
                }
            }
            else
            {
                if ( bFirst )
                    bFirst = false;
                else
                {
                    sql.Append ( ", " );
                    values.Append ( ", " );
                }
                sql.Append ("[");
                sql.Append ( column.ColumnName );
                sql.Append ("]");

                //values.Append (myRow[column.ColumnName].ToString() );

                if (myRow[column.ColumnName].ToString() == "True")
                    values.Append("1");
                else if (myRow[column.ColumnName].ToString() == "False")
                    values.Append("0");
                else if(myRow[column.ColumnName] == System.DBNull.Value)    
                    values.Append ("NULL");
                else if(column.DataType.ToString().Equals("System.String"))
                {
                    values.Append("'"+myRow[column.ColumnName].ToString()+"'");
                }
                else
                    values.Append (myRow[column.ColumnName].ToString());
                    //values.Append (column.DataType.ToString() );
            }
        }
        sql.Append ( ") " );
        sql.Append ( values.ToString () );
        sql.Append ( ")" );

        if ( bIdentity )
        {
            sql.Append ( "; SELECT CAST(scope_identity() AS " );
            sql.Append ( identityType );
            sql.Append ( ")" );
        }
        bFirst = true;
        sql.Append(";");
        values = new StringBuilder ( "VALUES (" );
    } //fin foreach
    return sql.ToString ();
}

0

ฉันได้แก้ไขปัญหานี้ครั้งแรกโดยใช้ DBCC แล้วใช้การแทรก ตัวอย่างเช่นหากตารางของคุณคือ

ก่อนอื่นให้ตั้งค่า ID ปัจจุบันใหม่บนตารางเป็น NEW_RESEED_VALUE

MyTable {IDCol, colA, colB}

    DBCC CHECKIDENT('MyTable', RESEED, NEW_RESEED_VALUE)

จากนั้นคุณสามารถใช้

    insert into MyTable (colA, ColB) select colA, colB from MyTable

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


1
นี่เป็นความคิดที่ดี แต่ New_reseed_value เป็นเมล็ดปัจจุบันและหมายเลขถัดไปที่จะใช้จะมากกว่า 1 ค่านั้น ดังนั้นหากคุณต้องการให้แถวที่แทรกถัดไปเป็นข้อมูลเฉพาะตัว 10 ดังนั้น NEW_RESEED_VALUE ต้องถูกตั้งค่าเป็น 9
LarryBud

0

คุณสามารถสร้างตารางใหม่โดยใช้รหัสต่อไปนี้

SELECT IDENTITY (int, 1, 1) AS id, column1, column2
INTO dbo.NewTable
FROM dbo.OldTable

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


0

หากคุณต้องการเปลี่ยนค่าคีย์หลักเป็นหมายเลขอื่น (เช่น 123 -> 1123) บล็อกคุณสมบัติเอกลักษณ์เปลี่ยนค่า PK ตั้ง Identity_insert จะไม่ทำงาน การแทรก / ลบไม่แนะนำให้เลือกถ้าคุณมีการลบแบบเรียงซ้อน (ยกเว้นว่าคุณปิดการตรวจสอบความสมบูรณ์ของการอ้างอิง)

สคริปต์นี้จะปิดตัวตนใน PK:

***********************

sp_configure 'allow update', 1
go
reconfigure with override
go


update syscolumns set colstat = 0 --turn off bit 1 which indicates identity column
where id = object_id('table_name') and name = 'column_name'
go


exec sp_configure 'allow update', 0
go
reconfigure with override
go

***********************

ถัดไปคุณสามารถตั้งค่าความสัมพันธ์เพื่อให้พวกเขาอัปเดตการอ้างอิงคีย์ต่างประเทศ มิฉะนั้นคุณต้องปิดการบังคับใช้ความสัมพันธ์ ลิงก์ SO นี้แสดงวิธีการ: ข้อ จำกัด foreign key สามารถปิดใช้งานชั่วคราวโดยใช้ T-SQL ได้อย่างไร

ตอนนี้คุณสามารถทำการอัปเดตของคุณได้ ฉันเขียนสคริปต์สั้น ๆ เพื่อเขียน SQL อัปเดตทั้งหมดของฉันตามชื่อคอลัมน์เดียวกัน (ในกรณีของฉันฉันต้องเพิ่ม CaseID 1,000,000:

select 
'update ['+c.table_name+'] SET ['+Column_Name+']=['+Column_Name+']+1000000'
from Information_Schema.Columns as c
JOIN Information_Schema.Tables as t ON t.table_Name=c.table_name and t.Table_Schema=c.table_schema and t.table_type='BASE TABLE'
where Column_Name like 'CaseID' order by Ordinal_position

สุดท้ายให้เปิดใช้งาน Referential Integrity อีกครั้งจากนั้นเปิดใช้งานคอลัมน์ Identity ใหม่บนคีย์หลัก

หมายเหตุ: ฉันเห็นบางคนในคำถามเหล่านี้ถามว่าทำไม ในกรณีของฉันฉันต้องรวมข้อมูลจากอินสแตนซ์การผลิตที่สองลงในฐานข้อมูลหลักเพื่อให้ฉันสามารถปิดอินสแตนซ์ที่สอง ฉันต้องการข้อมูลการดำเนินการ PK / FK ทั้งหมดเพื่อไม่ให้ชนกัน FK ของ Meta-data เหมือนกัน

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