【问题标题】:How to update Identity Column in SQL Server?如何更新 SQL Server 中的标识列?
【发布时间】:2013-10-09 22:47:40
【问题描述】:

我有 SQL Server 数据库,我想更改标识列,因为它已启动 有一个很大的数字10010,它与另一个表相关,现在我有 200 条记录,我想在记录增加之前解决这个问题。

更改或重置此列的最佳方法是什么?

【问题讨论】:

    标签: sql sql-server tsql sql-server-2008


    【解决方案1】:

    您无法更新身份列。

    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
    

    【讨论】:

    • DBCC 重置下一条新记录,但我现在想要更改现有记录。
    • @sachin 这不是更新现有的 IDENTITY 这是手动插入
    • @PhillGreggan 是的,这是实现这一目标的最佳解决方案。您无法像更新普通列一样更新 Identity 列。
    • 这个接受的答案没有回答问题,即如何更新标识列(例如UPDATE YourTable SET IdentityCol = 13)。 SET IDENTITY_INSERT YourTable ON 只允许插入,不允许更新。
    • 我认为用“你不能...”来回答“如何...”问题没有用,或者至少不要将其投票为最佳答案不能解决问题。 @Luv 的回复确实解决了这个问题,尽管这不是一个简单的操作或设计上不推荐。
    【解决方案2】:

    如果你的问题是正确的,你想做类似的事情

    update table
    set identity_column_name = some value
    

    让我告诉你,这不是一个简单的过程,也不建议使用它,因为它可能会关联一些foreign key

    但是这里有步骤,请采取back-up的表

    步骤 1- 选择表格的设计视图

    第 2 步 - 关闭标识列

    现在您可以使用update 查询。

    现在redo第1步和第2步并打开身份列

    Reference

    【讨论】:

    • 我有另一个与这个表相关的表,我做不到
    • 因此声明不可取 :)
    • @AbdusalamElsherif 但是您问如何更改身份列。
    • @luv 至少你已经回答了被问到的问题
    • 我使用这个过程在我的开发数据库中设置 id。如果有一个命令让我无论如何都可以这样做,那就太好了,但这有效。
    【解决方案3】:

    你需要

    set identity_insert YourTable ON
    

    然后删除您的行并以不同的身份重新插入。

    完成插入后,别忘了关闭 identity_insert

    set identity_insert YourTable OFF
    

    【讨论】:

    • 这比关闭列的身份要容易和安全得多!
    • 这对于少量记录来说更安全,更容易,但不能正确回答问题。关闭身份虽然更危险,有时甚至是不可能的,但确实允许您更新身份列。
    【解决方案4】:
    --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
    

    【讨论】:

    • 如果表非常大,只是一个性能提示,而不是对表执行删除操作,而是截断表 yourTable。它是瞬时的。但请注意,不要使用 truncate 回头,因为它没有被记录。
    【解决方案5】:

    尝试使用DBCC CHECKIDENT

    DBCC CHECKIDENT ('YourTable', RESEED, 1);
    

    【讨论】:

      【解决方案6】:
      DBCC CHECKIDENT(table_name, RESEED, value)
      

      table_name = 给表你要重置的值

      value=初始值为零,标识列以 1 开始

      【讨论】:

        【解决方案7】:

        将您的表复制到没有标识列的新表中。

            select columns into newtable from yourtable
        

        使用新种子将标识列添加到 newtable 并将其作为主键

            ALTER TABLE tableName ADD id MEDIUMINT NOT NULL AUTO_INCREMENT KEY
        

        【讨论】:

          【解决方案8】:
          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 不允许您在未指定的情况下插入

          【讨论】:

            【解决方案9】:

            您还可以使用SET IDENTITY INSERT 允许您将值插入标识列。

            例子:

            SET IDENTITY_INSERT dbo.Tool ON
            GO
            

            然后您可以在标识列中插入您需要的值。

            【讨论】:

              【解决方案10】:
              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
              

              但是上面的代码只有在没有主外键关系的情况下才有效

              【讨论】:

                【解决方案11】:

                C# 程序员使用命令生成器的完整解决方案

                首先,你要知道这些事实:

                • 在任何情况下,您都无法修改标识列,因此您必须删除该行并重新添加新标识。
                • 您不能从列中删除标识属性(您必须从列中删除)
                • .net 的自定义命令生成器总是跳过标识列,因此您不能将其用于此目的。

                所以,一旦知道了这一点,你要做的就是。要么编写你自己的 SQL 插入语句,要么编写你自己的插入命令生成器。或者使用我为你编程的这个。给定一个 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 ();
                }
                

                【讨论】:

                  【解决方案12】:

                  我先用 DBCC 再用 insert 解决了这个问题。例如,如果您的表是

                  首先在表上设置新的当前 ID 值为 NEW_RESEED_VALUE

                  我的表{ IDCol, 可乐, colB }

                      DBCC CHECKIDENT('MyTable', RESEED, NEW_RESEED_VALUE)
                  

                  那么你可以使用

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

                  这将复制您的所有记录,但使用以 NEW_RESEED_VALUE 开头的新 IDCol 值。一旦您删除/移动了它们的外键引用(如果有),您就可以删除更高 ID 值的重复行。

                  【讨论】:

                  • 这是一个不错的主意,但 New_reseed_value 是当前种子,下一个将使用的数字将比该值大 1。因此,如果您希望下一个插入的行是标识 10,则 NEW_RESEED_VALUE 必须设置为 9。
                  【解决方案13】:

                  您可以使用以下代码创建一个新表。

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

                  然后删除旧数据库,并将新数据库重命名为旧数据库的名称。 注意:column1 和column2 代表旧表中要保留在新表中的所有列。

                  【讨论】:

                    【解决方案14】:

                    如果您特别需要将主键值更改为不同的数字(例如 123 -> 1123)。身份属性阻止更改 PK 值。设置 Identity_insert 不起作用。如果您有级联删除,则不建议执行插入/删除(除非您关闭参照完整性检查)。

                    编辑:较新版本的 SQL 不允许更改 syscolumns 实体,因此我的部分解决方案必须以艰难的方式完成。请参阅此 SO,了解如何从主键中删除身份: Remove Identity from a column in a table 此脚本将关闭 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 链接显示了如何: How can foreign key constraints be temporarily disabled using 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
                    

                    最后,重新启用参照完整性,然后重新启用主键上的标识列。

                    注意:我看到有些人在这些问题上问为什么。就我而言,我必须将来自第二个生产实例的数据合并到一个主数据库中,这样我才能关闭第二个实例。我只需要操作数据的所有 PK/FK 不会发生冲突。元数据 FK 是相同的。

                    【讨论】:

                    • 当我这样做的时候它起作用了,这就是为什么我把它全部写下来的原因
                    • 从不支持直接更新 syscolumns,上次在 SQL Server 2000 上工作。在 SQL Server 2005 中,syscolumns 被替换为视图,现在您将收到错误:Ad hoc updates to system catalogs are not allowed. 您可以看到使用sp_helptext 'sys.syscolumns'查看文本
                    • 在 SQL2005 上工作。现在版本问题很重要,但下次以该信息为先。要在较新版本上执行我建议的操作,可能需要克隆标识列并删除原始列,进行值更新,然后将替换列提升回标识。
                    • 刚刚在 SQL 2005 SP2 (9.00.3042.00) 上进行了测试,它以 Ad hoc updates to system catalogs are not allowed. 失败
                    【解决方案15】:

                    我遇到了类似的问题,我需要更新一些 ID,我所做的是(我需要将它们增加 10k):

                    set identity_insert YourTable ON
                    
                    INSERT INTO YourTable 
                       ([ID]
                       ,[something1]
                       ,[something2]
                       ,[something3])
                    SELECT 
                       ([ID] + 10000)
                       ,[something1]
                       ,[something2]
                       ,[something3]) 
                    FROM YourTable
                    WHERE something1 = 'needs updeted id' 
                       AND something2 = 'some other condition'
                    
                    set identity_insert YourTable OFF
                    
                    DELETE FROM YourTable 
                    WHERE ID >= 'your old ID From' 
                       AND ID <= 'Your old ID To' 
                    

                    就是这样。希望你理解这个逻辑,在我的例子中,还有 PK-FK 键与其他表的连接,这意味着我必须更新它们,然后才能从 'YourTable' 原始行中删除。

                    我知道这个问题已经有了答案,我只是想以 SQL 查询为例,

                    【讨论】:

                      【解决方案16】:

                      我做了以下事情:

                      1. 将相关数据移动到临时存储中
                      2. 更新主键/标识列值(删除和创建约束)
                      3. 使用新的外键值重新插入相关数据

                      我将我的解决方案包装在一个存储过程中:

                      CREATE PROCEDURE [dbo].[UpdateCustomerLocationId]
                          @oldCustomerLocationId INT,
                          @newCustomerLocationId INT
                      AS
                        /* 
                          Updates CustomerLocation.CustomerLocationId @oldCustomerLocationId to @newCustomerLocationId
                          
                          Example:
                              EXEC [dbo].[UpdateCustomerLocationId] 
                                  @oldCustomerLocationId = 6154874, 
                                  @newCustomerLocationId = 50334;
                          */
                      
                      BEGIN
                      
                          SET NOCOUNT ON;
                          
                          -- exit if @oldCustomerLocationId does not exists
                          IF NOT EXISTS (SELECT * FROM dbo.CustomerLocation cl WHERE cl.CustomerLocationId = @oldCustomerLocationId)
                          BEGIN
                              PRINT CONCAT('CustomerLocationId ''', @oldCustomerLocationId, ''' (@oldCustomerLocationId) does not exist in dbo.CustomerLocation');
                              RETURN 1; -- 0 = success, > 0 = failure
                          END
                      
                          -- exit if @newCustomerLocationId already exists
                          IF EXISTS (SELECT * FROM dbo.CustomerLocation cl WHERE cl.CustomerLocationId = @newCustomerLocationId)
                          BEGIN
                              PRINT CONCAT('CustomerLocationId ''', @newCustomerLocationId, ''' (@newCustomerLocationId) already exists in dbo.CustomerLocation');
                              RETURN 2; -- 0 = success, > 0 = failure
                          END
                          
                      
                          BEGIN TRAN;
                      
                      
                              BEGIN -- MOVE related data into temporary storage
                      
                                  IF EXISTS (SELECT * FROM dbo.CustomerLocationData t WHERE t.CustomerLocationId = @oldCustomerLocationId) BEGIN
                          
                                      IF OBJECT_ID('tempdb..#CustomerLocationData') IS NOT NULL
                                          DROP TABLE #CustomerLocationData;
                      
                                      SELECT * INTO #CustomerLocationData FROM dbo.CustomerLocationData t WHERE t.CustomerLocationId = @oldCustomerLocationId;
                                      DELETE t FROM dbo.CustomerLocationData t WHERE t.CustomerLocationId = @oldCustomerLocationId;
                      
                                  END
                      
                              END
                      
                      
                              BEGIN -- UPDATE dbo.CustomerLocation
                      
                                  -- DROP CONSTRAINTs
                                  ALTER TABLE [dbo].[CustomerLocation] DROP CONSTRAINT [UC_CustomerLocation];
                      
                                  -- INSERT OLD record with new CustomerLocationId
                                  SET IDENTITY_INSERT dbo.CustomerLocation ON;
                      
                                  INSERT INTO dbo.CustomerLocation
                                  (
                                      CustomerLocationId, CustomerId, LocationId, CustomerLocationIdent, CustomerLocationIdent2, LocationIdent, LocationName, CustomerDistrictId, 
                                      CustomerLocationGUID, UpdatedOn, IssueManager, EnrollSelfMonitoring, TemperatureControlDeadlineHour, CreatedOn, OperationBegin, ActiveCustomer, 
                                      Comments, LocationName2, ParentGroup, TempString1, TempString2, TempString3, TempString4, TempString5, AutoInheritFromLocation, ClassificationPrimary
                                  )
                                  SELECT @newCustomerLocationId AS CustomerLocationId, CustomerId,LocationId, CustomerLocationIdent, CustomerLocationIdent2, LocationIdent, LocationName, CustomerDistrictId,
                                      CustomerLocationGUID, UpdatedOn, IssueManager, EnrollSelfMonitoring, TemperatureControlDeadlineHour, CreatedOn, OperationBegin, ActiveCustomer,
                                      Comments,LocationName2, ParentGroup, TempString1, TempString2, TempString3, TempString4, TempString5, AutoInheritFromLocation, ClassificationPrimary
                                  FROM dbo.CustomerLocation 
                                  WHERE CustomerLocationId = @oldCustomerLocationId;
                      
                                  SET IDENTITY_INSERT dbo.CustomerLocation OFF;
                      
                                  -- DELETE OLD record
                                  DELETE cl FROM dbo.CustomerLocation cl WHERE cl.CustomerLocationId = @oldCustomerLocationId;
                      
                                  -- ADD CONSTRAINTS
                                  ALTER TABLE [dbo].[CustomerLocation] ADD CONSTRAINT [UC_CustomerLocation] UNIQUE NONCLUSTERED ([CustomerId], [LocationId]);
                      
                              END
                      
                      
                              BEGIN -- re-INSERT related data from temporary storage
                      
                                  IF OBJECT_ID('tempdb..#CustomerLocationData') IS NOT NULL BEGIN
                                      SET IDENTITY_INSERT dbo.CustomerLocationData ON;
                                      INSERT INTO dbo.CustomerLocationData (Guid, CustomerLocationId, CustomerLocationDataTypeId, Date, Category, Data)
                                      SELECT Guid, @newCustomerLocationId CustomerLocationId, CustomerLocationDataTypeId, Date, Category, Data FROM #CustomerLocationData;
                                      SET IDENTITY_INSERT dbo.CustomerLocationData OFF;
                                  END
                      
                              END
                      
                      
                          COMMIT TRAN;
                      
                      END
                      

                      【讨论】:

                        【解决方案17】:

                        这发生在我身上,因为我做了一个合并,更新了我正在执行合并的 ID。

                        无效的示例(注意 ClownID):

                            MERGE ArchitectMain.dbo.BackendClowns AS TGT 
                           USING (
                            SELECT ClownID
                                ,ClownName
                                ,Description
                                ,Active
                                ,EmailSubject
                                ,AddedBy
                                ,Added
                            FROM #temptable1
                            ) AS SRC(ClownID, ClownName, Description, Active, EmailSubject, AddedBy, Added)
                            ON (TGT.ClownID = SRC.ClownID)
                        WHEN MATCHED
                            THEN
                                UPDATE
                                SET ClownID = SRC.ClownID
                                    ,ClownName = SRC.ClownName
                                    ,Description = SRC.Description
                                    ,Active = SRC.Active
                                    ,EmailSubject = SRC.EmailSubject
                                    ,AddedBy = SRC.AddedBy
                                    ,Added = SRC.Added;
                        

                        有效的示例(注意 ClownID):

                        MERGE ArchitectMain.dbo.BackendClowns AS TGT
                        USING (
                            SELECT ClownID
                                ,ClownName
                                ,Description
                                ,Active
                                ,EmailSubject
                                ,AddedBy
                                ,Added
                            FROM #temptable1
                            ) AS SRC(ClownID, ClownName, Description, Active, EmailSubject, AddedBy, Added)
                            ON (TGT.ClownID = SRC.ClownID)
                        WHEN MATCHED
                            THEN
                                UPDATE
                                SET ClownName = SRC.ClownName
                                    ,Description = SRC.Description
                                    ,Active = SRC.Active
                                    ,EmailSubject = SRC.EmailSubject
                                    ,AddedBy = SRC.AddedBy
                                    ,Added = SRC.Added;
                                    
                        

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 2018-08-31
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2011-04-11
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多