英文:
How do I add Auto Increment to Existing SQL ID Primary Key?
问题
不能将空值插入到列 'ID',表 'DB_9CF886_mcl959.dbo.Posts' 中;该列不允许为空。插入失败。
所以我尝试添加标识:
alter table dbo.Posts ADD ID INT IDENTITY(1,1) CONSTRAINT PK_Posts1 PRIMARY KEY CLUSTERED;
这给了我这个错误:
每个表中的列名必须是唯一的。表 'dbo.Posts' 中的列名 'ID' 被指定了多次。
我可以删除表并重新创建它,但我想知道如何修复它以将标识添加到ID列。
数据库的截图:dbo.Posts
英文:
I have an empty table that I thought was auto increment until I tried adding my first record. That's when SQL told me this:
> Cannot insert the value NULL into column 'ID', table 'DB_9CF886_mcl959.dbo.Posts'; column does not allow nulls. INSERT fails.
So I tried to add the identity to it:
alter table dbo.Posts ADD ID INT IDENTITY(1,1) CONSTRAINT PK_Posts1 PRIMARY KEY CLUSTERED;
That gave me this error:
> Column names in each table must be unique. Column name 'ID' in table 'dbo.Posts' is specified more than once.
I could drop the table and recreate it, but I'd like to know how to FIX IT to add the identity to the ID column.
Screenshot of database: dbo.Posts
答案1
得分: 4
以下是翻译好的部分:
虽然不能将IDENTITY
添加到现有列,并且将IDENTITY
添加到现有表意味着添加一个新列是正确的,但也可以不使用IDENTITY
,也不需要DROP
任何内容。
相反,可以使用SEQUENCE
对象来修改现有的ID
列以获取新值,这与IDENTITY
具有(实际上)相同的最终结果,但这样可以保留现有的ID
列值,保留外键引用,并保留CLUSTERED
索引,而无需重建表格。
请执行以下操作:
SET XACT_ABORT ON;
BEGIN TRANSACTION;
DECLARE @baseId int = ( SELECT ISNULL( MAX( ID ), 0 ) FROM dbo.Posts ) + 1;
-- https://learn.microsoft.com/en-us/sql/t-sql/statements/create-sequence-transact-sql
CREATE SEQUENCE dbo.PostsIdSequence START WITH @baseId INCREMENT BY 1;
ALTER TABLE dbo.Posts
ADD CONSTRAINT DF_Posts_Sequence DEFAULT NEXT VALUE FOR dbo.PostsIdSequence FOR "ID";
COMMIT TRANSACTION;
英文:
While it's true that you cannot add IDENTITY
to an existing column, and that adding IDENTITY
to an existing table means adding a new column - it's also true that you don't need to use IDENTITY
- nor do you need to DROP
anything either.
Instead, ALTER
your existing ID
column to use a SEQUENCE
object for new values - which has (effectively) the same end-result as IDENTITY
- but this way it will preserve your existing ID
column values, preserve foreign-key references, and preserve your CLUSTERED
index without needing a table rebuild.
Do this:
SET XACT_ABORT ON;
BEGIN TRANSACTION;
DECLARE @baseId int = ( SELECT ISNULL( MAX( ID ), 0 ) FROM dbo.Posts ) + 1;
-- https://learn.microsoft.com/en-us/sql/t-sql/statements/create-sequence-transact-sql
CREATE SEQUENCE dbo.PostsIdSequence START WITH @baseId INCREMENT BY 1;
ALTER TABLE dbo.Posts
ADD CONSTRAINT DF_Posts_Sequence DEFAULT NEXT VALUE FOR dbo.PostsIdSequence FOR "ID";
COMMIT TRANSACTION;
答案2
得分: 3
以下是一个示例,使用SWITCH
将数据移动到具有相同模式且已具有IDENTITY
的另一个表中。
--创建示例表和数据
CREATE TABLE dbo.AddIdentityExample(
IncrementalColumn int NOT NULL
CONSTRAINT PK_AddIdentityExample PRIMARY KEY
, OtherData varchar(20) NULL
);
CREATE INDEX idx_AddIdentityExample_OtherData
ON dbo.AddIdentityExample(OtherData);
INSERT INTO dbo.AddIdentityExample VALUES
(1, '样本数据一')
, (2, '样本数据二')
, (3, '样本数据三');
GO
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRAN;
--创建具有相同模式、索引和约束的临时表
CREATE TABLE dbo.AddIdentityExampleStaging(
IncrementalColumn int IDENTITY NOT NULL --添加IDENTITY列属性
CONSTRAINT PK_AddIdentityExampleStaging PRIMARY KEY
, OtherData varchar(20) NULL
);
CREATE INDEX idx_AddIdentityExampleStaging_OtherData
ON dbo.AddIdentityExampleStaging(OtherData);
--将数据从源表移动到新表
ALTER TABLE dbo.AddIdentityExample
SWITCH TO dbo.AddIdentityExampleStaging;
DROP TABLE dbo.AddIdentityExample;
--重命名表
EXEC sp_rename
@objname = N'dbo.AddIdentityExampleStaging'
, @newname = N'AddIdentityExample'
, @objtype = 'OBJECT';
--重命名约束
EXEC sp_rename
@objname = N'dbo.PK_AddIdentityExampleStaging'
, @newname = N'PK_AddIdentityExample'
, @objtype = 'OBJECT';
--重命名索引
EXEC sp_rename
@objname = N'dbo.AddIdentityExample.idx_AddIdentityExampleStaging_OtherData'
, @newname = N'idx_AddIdentityExampleStaging_OtherData'
, @objtype = N'INDEX';
--使用当前最大列值设置IDENTITY种子
DBCC CHECKIDENT(N'dbo.AddIdentityExample');
COMMIT;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0 ROLLBACK;
THROW;
END CATCH;
GO
英文:
Below is an example that uses SWITCH
to move data into another table of identical schema that already has the IDENTITY
.
--create sample table and data
CREATE TABLE dbo.AddIdentityExample(
IncrementalColumn int NOT NULL
CONSTRAINT PK_AddIdentityExample PRIMARY KEY
, OtherData varchar(20) NULL
);
CREATE INDEX idx_AddIdentityExample_OtherData
ON dbo.AddIdentityExample(OtherData);
INSERT INTO dbo.AddIdentityExample VALUES
(1, 'Sample data one')
, (2, 'Sample data two')
, (3, 'Sample data three');
GO
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRAN;
--create staging table with same schema, indexes, and constraints
CREATE TABLE dbo.AddIdentityExampleStaging(
IncrementalColumn int IDENTITY NOT NULL --IDENTITY column property added
CONSTRAINT PK_AddIdentityExampleStaging PRIMARY KEY
, OtherData varchar(20) NULL
);
CREATE INDEX idx_AddIdentityExampleStaging_OtherData
ON dbo.AddIdentityExampleStaging(OtherData);
--move data from source table into new table
ALTER TABLE dbo.AddIdentityExample
SWITCH TO dbo.AddIdentityExampleStaging;
DROP TABLE dbo.AddIdentityExample;
--rename table
EXEC sp_rename
@objname = N'dbo.AddIdentityExampleStaging'
, @newname = N'AddIdentityExample'
, @objtype = 'OBJECT';
--rename constraints
EXEC sp_rename
@objname = N'dbo.PK_AddIdentityExampleStaging'
, @newname = N'PK_AddIdentityExample'
, @objtype = 'OBJECT';
--rename indexes
EXEC sp_rename
@objname = N'dbo.AddIdentityExample.idx_AddIdentityExampleStaging_OtherData'
, @newname = N'idx_AddIdentityExampleStaging_OtherData'
, @objtype = N'INDEX';
--seed IDENTITY with current max column value
DBCC CHECKIDENT(N'dbo.AddIdentityExample');
COMMIT;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0 ROLLBACK;
THROW;
END CATCH;
GO
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论