我有 SQL Server 数据库,我想更改标识列,因为它以一个大数字开头,10010
并且与另一个表相关,现在我有 200 条记录,我想在记录增加之前解决这个问题。
更改或重置此列的最佳方法是什么?
我有 SQL Server 数据库,我想更改标识列,因为它以一个大数字开头,10010
并且与另一个表相关,现在我有 200 条记录,我想在记录增加之前解决这个问题。
更改或重置此列的最佳方法是什么?
您不能更新标识列。
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
如果你的问题是正确的,你想做类似的事情
update table
set identity_column_name = some value
让我告诉你,这不是一个简单的过程,也不建议使用它,因为它可能有一些foreign key
关联。
但这里有一些步骤,请拿一张back-up
桌子
步骤 1- 选择表格的设计视图
第 2 步 - 关闭身份列
现在您可以使用update
查询。
现在redo
是第 1 步和第 2 步,并打开身份列
你需要
set identity_insert YourTable ON
然后删除您的行并以不同的身份重新插入。
完成插入后,不要忘记关闭 identity_insert
set identity_insert YourTable OFF
--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
尝试使用DBCC CHECKIDENT
:
DBCC CHECKIDENT ('YourTable', RESEED, 1);
DBCC CHECKIDENT(table_name, RESEED, value)
table_name = 给你要重置的表值
值=初始值为零,以 1 开始标识列
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 不允许您在不指定它们的情况下插入
将您的表复制到没有标识列的新表中。
select columns into newtable from yourtable
使用新种子将标识列添加到 newtable 并将其作为主键
ALTER TABLE tableName ADD id MEDIUMINT NOT NULL AUTO_INCREMENT KEY
使用命令生成器的 C# 程序员的完整解决方案
首先,您必须了解以下事实:
所以,一旦知道了,你要做的就是。要么编写你自己的 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 ();
}
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
然而,上面的代码只有在没有主外键关系的情况下才有效
我有类似的问题我需要更新一些我所做的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 查询为例,
我首先使用 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 值重复行。
您可以使用以下代码创建一个新表。
SELECT IDENTITY (int, 1, 1) AS id, column1, column2
INTO dbo.NewTable
FROM dbo.OldTable
然后删除旧数据库,并将新数据库重命名为旧数据库的名称。注意: column1 和 column2 代表旧表中要保留在新表中的所有列。
如果您特别需要将主键值更改为不同的数字(例如 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 是相同的。
我做了以下事情:
我将我的解决方案包装在一个存储过程中:
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
这发生在我身上,因为我做了一个合并,更新了我正在合并的 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;