[英]Remove Identity from a column in a table
We have a 5GB table (nearly 500 million rows) and we want to remove the identity property on one of the column, but when we try to do this through SSMS - it times out.我们有一个 5GB 的表(将近 5 亿行),我们想删除其中一列的标识属性,但是当我们尝试通过 SSMS 执行此操作时 - 它超时了。
Can this be done through T-SQL?这可以通过 T-SQL 完成吗?
You cannot remove an IDENTITY
specification once set. IDENTITY
规范一旦设置就无法删除。
To remove the entire column:要删除整个列:
ALTER TABLE yourTable
DROP COLUMN yourCOlumn;
Information about ALTER TABLE here此处有关ALTER TABLE 的信息
If you need to keep the data, but remove the IDENTITY
column, you will need to:如果您需要保留数据,但删除IDENTITY
列,则需要:
IDENTITY
column to the new column将数据从现有IDENTITY
列转移到新列IDENTITY
column.删除现有的IDENTITY
列。If you want to do this without adding and populating a new column , without reordering the columns , and with almost no downtime because no data is changing on the table, let's do some magic with partitioning functionality (but since no partitions are used you don't need Enterprise edition):如果您想在不添加和填充新列的情况下执行此操作,而不对列重新排序,并且由于表上没有数据更改而几乎没有停机时间,那么让我们使用分区功能来做一些魔术(但由于没有使用分区,您不不需要企业版):
ALTER TABLE [Original] SWITCH TO [Original2]
运行ALTER TABLE [Original] SWITCH TO [Original2]
exec sys.sp_rename
to rename the various schema objects back to the original names, and then you can recreate your foreign keys.删除原始(现在为空的表), exec sys.sp_rename
将各种架构对象重命名回原始名称,然后您可以重新创建外键。For example, given:例如,给定:
CREATE TABLE Original
(
Id INT IDENTITY PRIMARY KEY
, Value NVARCHAR(300)
);
CREATE NONCLUSTERED INDEX IX_Original_Value ON Original (Value);
INSERT INTO Original
SELECT 'abcd'
UNION ALL
SELECT 'defg';
You can do the following:您可以执行以下操作:
--create new table with no IDENTITY
CREATE TABLE Original2
(
Id INT PRIMARY KEY
, Value NVARCHAR(300)
);
CREATE NONCLUSTERED INDEX IX_Original_Value2 ON Original2 (Value);
--data before switch
SELECT 'Original', *
FROM Original
UNION ALL
SELECT 'Original2', *
FROM Original2;
ALTER TABLE Original SWITCH TO Original2;
--data after switch
SELECT 'Original', *
FROM Original
UNION ALL
SELECT 'Original2', *
FROM Original2;
--clean up
IF NOT EXISTS (SELECT * FROM Original) DROP TABLE Original;
EXEC sys.sp_rename 'Original2.IX_Original_Value2', 'IX_Original_Value', 'INDEX';
EXEC sys.sp_rename 'Original2', 'Original', 'OBJECT';
UPDATE Original
SET Id = Id + 1;
SELECT *
FROM Original;
This gets messy with foreign and primary key constraints, so here's some scripts to help you on your way:这会因外键和主键约束而变得混乱,因此这里有一些脚本可以帮助您:
First, create a duplicate column with a temporary name:首先,创建一个具有临时名称的重复列:
alter table yourTable add tempId int NOT NULL default -1;
update yourTable set tempId = id;
Next, get the name of your primary key constraint:接下来,获取主键约束的名称:
SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'yourTable';
Now try drop the primary key constraint for your column:现在尝试删除列的主键约束:
ALTER TABLE yourTable DROP CONSTRAINT PK_yourTable_id;
If you have foreign keys, it will fail, so if so drop the foreign key constraints.如果您有外键,它将失败,因此如果有,请删除外键约束。 KEEP TRACK OF WHICH TABLES YOU RUN THIS FOR SO YOU CAN ADD THE CONSTRAINTS BACK IN LATER!!!跟踪您运行此表的表,以便您可以在以后添加约束!!!
SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'otherTable';
alter table otherTable drop constraint fk_otherTable_yourTable;
commit;
..
Once all of your foreign key constraints have been removed, you'll be able to remove the PK constraint, drop that column, rename your temp column, and add the PK constraint to that column:删除所有外键约束后,您将能够删除 PK 约束,删除该列,重命名临时列,并将 PK 约束添加到该列:
ALTER TABLE yourTable DROP CONSTRAINT PK_yourTable_id;
alter table yourTable drop column id;
EXEC sp_rename 'yourTable.tempId', 'id', 'COLUMN';
ALTER TABLE yourTable ADD CONSTRAINT PK_yourTable_id PRIMARY KEY (id)
commit;
Finally, add the FK constraints back in:最后,将 FK 约束添加回:
alter table otherTable add constraint fk_otherTable_yourTable foreign key (yourTable_id) references yourTable(id);
..
El Fin!埃尔芬!
I just had this same problem.我刚刚遇到了同样的问题。 4 statements in SSMS instead of using the GUI and it was very fast. SSMS 中的 4 条语句而不是使用 GUI,而且速度非常快。
Make a new column创建一个新列
alter table users add newusernum int;
Copy values over复制值
update users set newusernum=usernum;
Drop the old column删除旧列
alter table users drop column usernum;
Rename the new column to the old column name将新列重命名为旧列名
EXEC sp_RENAME 'users.newusernum' , 'usernum', 'COLUMN';
Following script removes Identity field for a column named 'Id'以下脚本删除名为“Id”的列的标识字段
Hope it helps.希望能帮助到你。
BEGIN TRAN
BEGIN TRY
EXEC sp_rename '[SomeTable].[Id]', 'OldId';
ALTER TABLE [SomeTable] ADD Id int NULL
EXEC ('UPDATE [SomeTable] SET Id = OldId')
ALTER TABLE [SomeTable] NOCHECK CONSTRAINT ALL
ALTER TABLE [SomeTable] DROP CONSTRAINT [PK_constraintName];
ALTER TABLE [SomeTable] DROP COLUMN OldId
ALTER TABLE [SomeTable] ALTER COLUMN [Id] INTEGER NOT NULL
ALTER TABLE [SomeTable] ADD CONSTRAINT PK_JobInfo PRIMARY KEY (Id)
ALTER TABLE [SomeTable] CHECK CONSTRAINT ALL
COMMIT TRAN
END TRY
BEGIN CATCH
ROLLBACK TRAN
SELECT ERROR_MESSAGE ()
END CATCH
Bellow code working as fine, when we don't know identity column name .当我们不知道标识列名称时,波纹管代码可以正常工作。
Need to copy data into new temp table like Invoice_DELETED
.需要将数据复制到新的临时表中,如Invoice_DELETED
。 and next time we using:下次我们使用:
insert into Invoice_DELETED select * from Invoice where ...
SELECT t1.*
INTO Invoice_DELETED
FROM Invoice t1
LEFT JOIN Invoice ON 1 = 0
--WHERE t1.InvoiceID = @InvoiceID
For more explanation see: https://dba.stackexchange.com/a/138345/101038更多解释请参见: https : //dba.stackexchange.com/a/138345/101038
ALTER TABLE tablename add newcolumn int
update tablename set newcolumn=existingcolumnname
ALTER TABLE tablename DROP COLUMN existingcolumnname;
EXEC sp_RENAME 'tablename.oldcolumn' , 'newcolumnname', 'COLUMN'
However above code works only if no primary-foreign key relation但是上面的代码只有在没有主外键关系时才有效
Just for someone who have the same problem I did.仅适用于与我遇到相同问题的人。 If you just want to make some insert just once you can do something like this.如果你只想插入一次,你可以做这样的事情。
Lets suppose you have a table with two columns假设您有一个包含两列的表格
ID Identity (1,1) | Name Varchar
and want to insert a row with the ID = 4. So you Reseed it to 3 so the next one is 4并且想要插入 ID = 4 的行。所以你将它重新播种到 3,所以下一个是 4
DBCC CHECKIDENT([YourTable], RESEED, 3)
Make the Insert插入
INSERT INTO [YourTable]
( Name )
VALUES ( 'Client' )
And get your seed back to the highest ID, lets suppose is 15让你的种子回到最高的 ID,假设是 15
DBCC CHECKIDENT([YourTable], RESEED, 15)
Done!完毕!
I had the same requirement, and you could try this way, which I personally recommend you, please manually design your table and generate the script, and what I did below was renaming the old table and also its constraint for backup.我有同样的要求,你可以试试这种方式,我个人推荐你,请手动设计你的表并生成脚本,我下面所做的是重命名旧表及其备份约束。
/* To prevent any potential data loss issues, you should review this script in detail before running it outside the context of the database designer.*/
BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
ALTER TABLE dbo.SI_Provider_Profile
DROP CONSTRAINT DF_SI_Provider_Profile_SIdtDateTimeStamp
GO
ALTER TABLE dbo.SI_Provider_Profile
DROP CONSTRAINT DF_SI_Provider_Profile_SIbHotelPreLoaded
GO
CREATE TABLE dbo.Tmp_SI_Provider_Profile
(
SI_lProvider_Profile_ID int NOT NULL,
SI_lSerko_Integrator_Token_ID int NOT NULL,
SI_sSerko_Integrator_Provider varchar(50) NOT NULL,
SI_sSerko_Integrator_Profile varchar(50) NOT NULL,
SI_dtDate_Time_Stamp datetime NOT NULL,
SI_lProvider_ID int NULL,
SI_sDisplay_Name varchar(10) NULL,
SI_lPurchased_From int NULL,
SI_sProvider_UniqueID varchar(255) NULL,
SI_bHotel_Pre_Loaded bit NOT NULL,
SI_sSiteName varchar(255) NULL
) ON [PRIMARY]
GO
ALTER TABLE dbo.Tmp_SI_Provider_Profile SET (LOCK_ESCALATION = TABLE)
GO
ALTER TABLE dbo.Tmp_SI_Provider_Profile ADD CONSTRAINT
DF_SI_Provider_Profile_SIdtDateTimeStamp DEFAULT (getdate()) FOR SI_dtDate_Time_Stamp
GO
ALTER TABLE dbo.Tmp_SI_Provider_Profile ADD CONSTRAINT
DF_SI_Provider_Profile_SIbHotelPreLoaded DEFAULT ((0)) FOR SI_bHotel_Pre_Loaded
GO
IF EXISTS(SELECT * FROM dbo.SI_Provider_Profile)
EXEC('INSERT INTO dbo.Tmp_SI_Provider_Profile (SI_lProvider_Profile_ID, SI_lSerko_Integrator_Token_ID, SI_sSerko_Integrator_Provider, SI_sSerko_Integrator_Profile, SI_dtDate_Time_Stamp, SI_lProvider_ID, SI_sDisplay_Name, SI_lPurchased_From, SI_sProvider_UniqueID, SI_bHotel_Pre_Loaded, SI_sSiteName)
SELECT SI_lProvider_Profile_ID, SI_lSerko_Integrator_Token_ID, SI_sSerko_Integrator_Provider, SI_sSerko_Integrator_Profile, SI_dtDate_Time_Stamp, SI_lProvider_ID, SI_sDisplay_Name, SI_lPurchased_From, SI_sProvider_UniqueID, SI_bHotel_Pre_Loaded, SI_sSiteName FROM dbo.SI_Provider_Profile WITH (HOLDLOCK TABLOCKX)')
GO
-- Rename the primary key constraint or unique key In SQL Server constraints such as primary keys or foreign keys are objects in their own right, even though they are dependent upon the "containing" table.
EXEC sp_rename 'dbo.SI_Provider_Profile.PK_SI_Provider_Profile', 'PK_SI_Provider_Profile_Old';
GO
-- backup old table in case of
EXECUTE sp_rename N'dbo.SI_Provider_Profile', N'SI_Provider_Profile_Old', 'OBJECT'
GO
EXECUTE sp_rename N'dbo.Tmp_SI_Provider_Profile', N'SI_Provider_Profile', 'OBJECT'
GO
ALTER TABLE dbo.SI_Provider_Profile ADD CONSTRAINT
PK_SI_Provider_Profile PRIMARY KEY NONCLUSTERED
(
SI_lProvider_Profile_ID
) WITH( PAD_INDEX = OFF, FILLFACTOR = 90, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
COMMIT TRANSACTION
In SQL Server you can turn on and off identity insert like this:在 SQL Server 中,您可以像这样打开和关闭标识插入:
SET IDENTITY_INSERT table_name ON SET IDENTITY_INSERT table_name ON
-- run your queries here -- 在此处运行您的查询
SET IDENTITY_INSERT table_name OFF SET IDENTITY_INSERT 表名关闭
ALTER TABLE TABLE_NAME MODIFY (COLUMN_NAME DROP IDENTITY);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.