256

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

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

4

17 回答 17

339

您不能更新标识列。

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
于 2013-10-03T09:41:44.513 回答
78

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

update table
set identity_column_name = some value

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

但这里有一些步骤,请拿一张back-up桌子

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

在此处输入图像描述

第 2 步 - 关闭身份列

在此处输入图像描述

现在您可以使用update查询。

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

参考

于 2013-10-03T10:00:13.120 回答
69

你需要

set identity_insert YourTable ON

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

完成插入后,不要忘记关闭 identity_insert

set identity_insert YourTable OFF
于 2013-10-03T11:57:35.097 回答
26
--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
于 2015-04-02T11:47:01.717 回答
14

尝试使用DBCC CHECKIDENT

DBCC CHECKIDENT ('YourTable', RESEED, 1);
于 2013-10-03T09:41:38.030 回答
5
DBCC CHECKIDENT(table_name, RESEED, value)

table_name = 给你要重置的表值

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

于 2013-10-03T13:50:57.420 回答
5
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 不允许您在不指定它们的情况下插入

于 2019-04-15T11:45:37.457 回答
4

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

    select columns into newtable from yourtable

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

    ALTER TABLE tableName ADD id MEDIUMINT NOT NULL AUTO_INCREMENT KEY
于 2014-09-03T06:41:06.420 回答
2

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

例子:

SET IDENTITY_INSERT dbo.Tool ON
GO

然后您可以将所需的值插入到标识列中。

于 2013-10-03T09:43:09.277 回答
1

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

首先,您必须了解以下事实:

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

所以,一旦知道了,你要做的就是。要么编写你自己的 SQL 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 ();
}
于 2014-02-14T11:24:00.793 回答
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

然而,上面的代码只有在没有主外键关系的情况下才有效

于 2018-09-27T07:13:11.000 回答
1

我有类似的问题我需要更新一些我所做的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 查询为例,

于 2021-05-26T21:32:09.380 回答
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

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

于 2014-04-14T11:46:43.307 回答
0

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

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

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

于 2016-08-29T22:55:29.763 回答
0

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

编辑:较新版本的 SQL 不允许更改 syscolumns 实体,因此我的部分解决方案必须以艰难的方式完成。请参阅此 SO,了解如何从主键中 删除身份:从表中的列中删除身份 此脚本将关闭 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 链接显示了 如何使用 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 是相同的。

于 2019-10-23T20:08:39.113 回答
0

我做了以下事情:

  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
于 2021-10-30T21:54:06.193 回答
0

这发生在我身上,因为我做了一个合并,更新了我正在合并的 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;
            
于 2022-01-05T19:29:16.207 回答