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 中的任何行的情况下合并两个表?

如何在不使用数据透视和反透视的情况下在 SQL Server 中水平显示数据?

如何在不丢失 Xampp 中的数据的情况下将类型从 varchar 更改为 Date

如何在不使用pivot和unpivot的情况下在SQL Server中水平显示数据?

如何在不丢失 docker 数据的情况下更新 prometheus 配置文件

如何在不更改现有数据位置的情况下添加新的 SQL Server 分区范围来容纳未来的数据?