SQL Server,如何在不丢失数据的情况下创建表后设置自动增量?
Posted
技术标签:
【中文标题】SQL Server,如何在不丢失数据的情况下创建表后设置自动增量?【英文标题】:SQL Server, How to set auto increment after creating a table without data loss? 【发布时间】:2011-08-30 09:15:25 【问题描述】:我在 SQL Server 2008 中有一个表 table1
,其中有记录。
我希望主键 table1_Sno
列是一个自动递增的列。这可以在没有任何数据传输或表克隆的情况下完成吗?
我知道我可以使用 ALTER TABLE 添加自动增量列,但我可以简单地将 AUTO_INCREMENT 选项添加到作为主键的现有列吗?
【问题讨论】:
不确定您是否可以这样做:请参阅***.com/questions/4862385/… 【参考方案1】:下面的脚本可能是一个很好的解决方案。也适用于大数据。
ALTER DATABASE WMlive SET RECOVERY SIMPLE WITH NO_WAIT
ALTER TABLE WMBOMTABLE DROP CONSTRAINT PK_WMBomTable
ALTER TABLE WMBOMTABLE 删除列 BOMID
ALTER TABLE WMBOMTABLE ADD BomID int IDENTITY(1, 1) NOT NULL;
ALTER TABLE WMBOMTABLE 添加约束 PK_WMBomTable PRIMARY KEY Clustered (BomID);
ALTER DATABASE WMlive SET RECOVERY FULL WITH NO_WAIT
【讨论】:
【参考方案2】:如果您想通过设计器执行此操作,可以按照此处的说明进行操作 "Save changes is not permitted" when changing an existing column to be nullable
【讨论】:
【参考方案3】:更改IDENTITY
属性实际上只是元数据更改。但是直接更新元数据需要在单用户模式下启动实例,并在sys.syscolpars
中处理一些列,并且没有记录/不受支持,我不会推荐或提供任何其他详细信息。
到目前为止,对于在 SQL Server 2012+ 上遇到此答案的人来说,实现此自动递增列结果的最简单方法是创建一个 SEQUENCE
对象并将 next value for seq
设置为列默认值。
或者,或者对于以前的版本(从 2005 年开始),this connect item 上发布的解决方法显示了一种完全受支持的方法,无需使用 ALTER TABLE...SWITCH
进行数据操作的大小。还在 MSDN here 上写了博客。虽然实现这一点的代码不是很简单,并且存在一些限制 - 例如被更改的表不能成为外键约束的目标。
示例代码。
设置没有identity
列的测试表。
CREATE TABLE dbo.tblFoo
(
bar INT PRIMARY KEY,
filler CHAR(8000),
filler2 CHAR(49)
)
INSERT INTO dbo.tblFoo (bar)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM master..spt_values v1, master..spt_values v2
将其更改为具有 identity
列(或多或少是即时的)。
BEGIN TRY;
BEGIN TRANSACTION;
/*Using DBCC CHECKIDENT('dbo.tblFoo') is slow so use dynamic SQL to
set the correct seed in the table definition instead*/
DECLARE @TableScript nvarchar(max)
SELECT @TableScript =
'
CREATE TABLE dbo.Destination(
bar INT IDENTITY(' +
CAST(ISNULL(MAX(bar),0)+1 AS VARCHAR) + ',1) PRIMARY KEY,
filler CHAR(8000),
filler2 CHAR(49)
)
ALTER TABLE dbo.tblFoo SWITCH TO dbo.Destination;
'
FROM dbo.tblFoo
WITH (TABLOCKX,HOLDLOCK)
EXEC(@TableScript)
DROP TABLE dbo.tblFoo;
EXECUTE sp_rename N'dbo.Destination', N'tblFoo', 'OBJECT';
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 ROLLBACK TRANSACTION;
PRINT ERROR_MESSAGE();
END CATCH;
测试结果。
INSERT INTO dbo.tblFoo (filler,filler2)
OUTPUT inserted.*
VALUES ('foo','bar')
给予
bar filler filler2
----------- --------- ---------
10001 foo bar
清理
DROP TABLE dbo.tblFoo
【讨论】:
+1 巧妙的技巧,我不知道这种解决方法。看起来相当晦涩且无证,我认为如果人们不知道的话,他们不应该被否决。 @AaronBertrand - 同意。在另一个问题上不是我的 DV。 还应注意版本很重要。SWITCH
在 2005 年之前无法使用。我希望标记sql-server
也需要指定最低版本。不是为了这个问题的利益而这么说,而是可能作为这个问题的副本而被关闭的问题。
@AaronBertrand - BTW 对于其他情况也很有用,例如更改 ANSI_NULLS 选项或 working around this bug - drop duplicate unique constraint on ROWGUID column on FILESTREAM table
@RBarryYoung - 不。每个表都被视为至少一个分区。这适用于所有版本的 SQL Server。它只是将sys.partitions
中的object_id
更改为指向新对象。【参考方案4】:
是的,你可以。转到Tools > Designers > Table and Designers 并取消选中“Prevent Saving Changes That Prevent Table Recreation”。
【讨论】:
问题指定“没有数据传输”。 SSMS 创建一个新表并将所有数据复制到其中。【参考方案5】:SQL Server:如何在包含行的表上设置自动增量:
如果您要复制的表非常大,此策略会将行物理复制大约两次,这可能需要更长的时间。
您可以保存数据,使用自动增量和主键删除并重建表,然后重新加载数据。
我会用一个例子来指导你:
第一步,创建表foobar(无主键或自增):
CREATE TABLE foobar(
id int NOT NULL,
name nchar(100) NOT NULL,
)
第 2 步,插入一些行
insert into foobar values(1, 'one');
insert into foobar values(2, 'two');
insert into foobar values(3, 'three');
第 3 步,将 foobar 数据复制到临时表中:
select * into temp_foobar from foobar
第 4 步,删除表 foobar:
drop table foobar;
第 5 步,使用主键和自增属性重新创建表:
CREATE TABLE foobar(
id int primary key IDENTITY(1, 1) NOT NULL,
name nchar(100) NOT NULL,
)
第 6 步,将临时表中的数据插入 foobar
SET IDENTITY_INSERT temp_foobar ON
INSERT into foobar (id, name) select id, name from temp_foobar;
第 7 步,删除临时表,然后检查它是否有效:
drop table temp_foobar;
select * from foobar;
你应该得到这个,当你检查 foobar 表时,id 列是自动递增 1 并且 id 是主键:
1 one
2 two
3 three
【讨论】:
当我尝试此操作时,我收到错误“表 'temp_foobar' 没有身份属性。无法执行 SET 操作。”我错过了一步吗? 为了让它工作,我把它改成了“SET IDENTITY_INSERT foobar ON;”作为自己的声明。此外,我必须将 NOT FOR REPLICATION 选项设置为 Yes,否则在 INSERT 语句中出现“必须为标识列指定显式值”错误。 当我执行“SET IDENTITY_INSERT temp_foobar ON”时,我仍然得到“表'temp_foobar'没有身份属性。无法执行SET操作。”错误【参考方案6】:如果您不想添加新列,并且可以保证当前 int 列是唯一的,则可以将所有数据选择到临时表中,删除该表并使用指定的 IDENTITY 列重新创建.然后使用SET IDENTITY INSERT ON
可以将临时表中的所有数据插入到新表中。
【讨论】:
【参考方案7】:不,您不能向包含数据的现有列添加自动增量选项,我认为您提到的选项是最好的。
看看here。
【讨论】:
以上是关于SQL Server,如何在不丢失数据的情况下创建表后设置自动增量?的主要内容,如果未能解决你的问题,请参考以下文章
如何在不使用数据透视和反透视的情况下在 SQL Server 中水平显示数据?
如何在不丢失 Xampp 中的数据的情况下将类型从 varchar 更改为 Date
如何在不使用pivot和unpivot的情况下在SQL Server中水平显示数据?