向现有列添加身份


444

我需要将表的主键更改为标识列,并且表中已经有许多行。

我有一个脚本来清理ID,以确保它们从1开始是连续的,在我的测试数据库上可以正常工作。

将列更改为具有标识属性的SQL命令是什么?

Answers:


482

您不能更改现有的标识列。

您有2种选择,

  1. 使用标识创建一个新表并删除现有表

  2. 创建一个具有标识的新列并删除现有列

方法1.(新表)在这里,您可以将现有数据值保留在新创建的标识列上。

CREATE TABLE dbo.Tmp_Names
    (
      Id int NOT NULL
             IDENTITY(1, 1),
      Name varchar(50) NULL
    )
ON  [PRIMARY]
go

SET IDENTITY_INSERT dbo.Tmp_Names ON
go

IF EXISTS ( SELECT  *
            FROM    dbo.Names ) 
    INSERT  INTO dbo.Tmp_Names ( Id, Name )
            SELECT  Id,
                    Name
            FROM    dbo.Names TABLOCKX
go

SET IDENTITY_INSERT dbo.Tmp_Names OFF
go

DROP TABLE dbo.Names
go

Exec sp_rename 'Tmp_Names', 'Names'

方法2(新建列)您不能在新创建的标识列上保留现有数据值,标识列将保存数字序列。

Alter Table Names
Add Id_new Int Identity(1, 1)
Go

Alter Table Names Drop Column ID
Go

Exec sp_rename 'Names.Id_new', 'ID', 'Column'

有关更多详细信息,请参见以下Microsoft SQL Server论坛帖子:

如何将列更改为身份(1,1)


49
如果表数据很小,则此选项适用于gret。如果表很大,我更喜欢另一个选择:使用ALTER TABLE ... SWITCH将表架构替换为具有IDENTITY列但其他架构相同的另一个版本。ALTER TABLE .... SWITCH方法的优点是,由于不需要复制或更改任何表数据,因此它可以快速完成(对于十亿行表,不到5秒)。尽管有一些警告和限制。请参阅下面的详细信息。
贾斯汀·格兰特(

7
@Justin Grat:一个非常有趣的选择,我没有考虑过!之所以可行,是因为IDENTITY是列属性,而不是数据类型,因此SWITCH方法将两个表(旧表和新表)之间的模式验证为可识别的,而与IDENTITY的差异无关。感谢分享!
John Sansom

如果没有太多数据,则可以通过从SSMS生成脚本来实现“创建表”。右键单击表>“以清单形式记录”>“创建表至”(新的查询编辑器?)。然后将其删除,然后在该脚本中添加IDENTITY(1, 1)具有主键列的部分
goamn

也可以使用SSMS来强制执行此操作。转到工具>选项>设计器>取消选中“防止保存需要重新创建表的更改”。顺便说一句,不建议在相当大的表中使用。
Zafar

在PostgreSQL中,您可以使用以下命令将身份添加到现有的整数列中:
安德鲁·麦基

208

在SQL 2005及更高版本中,有一个技巧可以解决此问题,而无需更改表的数据页。这对于大型表很重要,因为在大表中触摸每个数据页可能需要几分钟或几小时。即使identity列是主键,是聚集索引或非聚集索引的组成部分,还是其他可能陷入较简单的“添加/删除/重命名列”解决方案的陷阱,该技巧也有效。

诀窍在于:您可以使用SQL Server的ALTER TABLE ... SWITCH语句来更改表的架构而不更改数据,这意味着您可以用具有相同表架构但没有IDENTITY列的IDENTITY替换表。可以使用相同的技巧将IDENTITY添加到现有列。

通常,ALTER TABLE ... SWITCH用于将分区表中的完整分区替换为新的空分区。但是它也可以在非分区表中使用。

我已使用此技巧在5秒钟内将25亿行表中的ID列从IDENTITY转换为非IDENTITY(以便运行一个多小时的查询,其查询计划对非IDENTITY更好列),然后又在不到5秒的时间内恢复了IDENTITY设置。

这是有关其工作方式的代码示例。

 CREATE TABLE Test
 (
   id int identity(1,1),
   somecolumn varchar(10)
 );

 INSERT INTO Test VALUES ('Hello');
 INSERT INTO Test VALUES ('World');

 -- copy the table. use same schema, but no identity
 CREATE TABLE Test2
 (
   id int NOT NULL,
   somecolumn varchar(10)
 );

 ALTER TABLE Test SWITCH TO Test2;

 -- drop the original (now empty) table
 DROP TABLE Test;

 -- rename new table to old table's name
 EXEC sp_rename 'Test2','Test';

 -- update the identity seed
 DBCC CHECKIDENT('Test');

 -- see same records
 SELECT * FROM Test; 

这显然比其他答案中的解决方案要复杂得多,但是,如果您的桌子很大,那将是真正的救命稻草。有一些警告:

  • 据我所知,唯一可以使用此方法更改表列的标识。不允许添加/删除列,更改可空性等。
  • 您需要先删除外键,然后再进行切换。
  • 与WITH SCHEMABINDING函数,视图等相同。
  • 新表的索引需要完全匹配(相同的列,相同的顺序等)
  • 新旧表必须位于同一文件组中。
  • 仅适用于SQL Server 2005或更高版本
  • 我以前认为该技巧仅适用于SQL Server的Enterprise或Developer版本(因为仅Enterprise和Developer版本支持分区),但是Mason G. Zhwiti在下面的评论中说,它也适用于SQL Standard Edition。我认为这意味着对Enterprise或Developer的限制不适用于ALTER TABLE ... SWITCH。

TechNet上有一篇很好的文章,详细介绍了上述要求。

更新-Eric Wu在下面的评论中添加了有关此解决方案的重要信息。将其复制到此处以确保引起更多关注:

这里还有另一个警告值得一提。尽管新表将很乐意接收旧表中的数据,并且所有新行都将按照身份模式插入,但它们将从1开始,并且如果所述列是主键,则可能会中断。考虑DBCC CHECKIDENT('<newTableName>')切换后立即运行。有关更多信息,请参见msdn.microsoft.com/en-us/library/ms176057.aspx

如果正在积极地用新行扩展表(这意味着在添加IDENTITY和添加新行之间没有太多的停机时间,那么DBCC CHECKIDENT您将需要手动在新表模式中将Identity Seed值设置为大于表中现有的最大ID,例如IDENTITY (2435457, 1),您可能可以在交易中同时包含ALTER TABLE...SWITCH和两者DBCC CHECKIDENT(或不-尚未对此进行测试),但是手动设置种子值似乎更容易,更安全。

显然,如果没有新行添加到表中(或者仅偶尔添加,例如每日ETL过程),那么就不会发生这种竞争情况DBCC CHECKIDENT


5
如果我的记忆正确,那么我可以从这篇文章中得到启发
贾斯汀·格兰特

2
仅供参考,这似乎也适用于SQL 2008 R2的标准版本。也许他们启用了此功能,就像他们现在启用了打开备份压缩功能一样。
Mason G. Zhwiti 2011年

3
@jbatista-OP的问题表明他已经在表上拥有一个主键,并且可以确保正确的值,但是他只是想将其更改为IDENTITY列。我在上面的回答集中在一个狭窄的用例上:如何在不实际更改任何数据的情况下将IDENTITY添加到列中。我上面记录的方法对于大型表来说节省了大量时间。如果您需要更改数据,则需要使用其他解决方案。
贾斯汀·格兰特

3
这里还有另一个警告值得一提。尽管新表将很乐意接收旧表中的数据,并且所有新行都将按照标识模式插入,但它们将从1开始,并且如果所述列是主键,则可能会中断。考虑DBCC CHECKIDENT('<newTableName>')切换后立即运行。有关更多信息,请参见msdn.microsoft.com/en-us/library/ms176057.aspx
Eric Wu

3
这是一个很好的答案!另请注意,列的可空性必须相同。因此,如果需要更改列可为空性,则必须在以后的步骤中进行操作。PK约束也是如此。我还更改了表创建中的标识值以匹配当前的最大值:IDENTITY(maxID + 1,1)
Philippe

71

您不能将列更改为IDENTITY列。您需要做的是从一开始就创建一个新列,将其定义为IDENTITY,然后删除旧列,并将新列重命名为旧名称。

ALTER TABLE (yourTable) ADD NewColumn INT IDENTITY(1,1)

ALTER TABLE (yourTable) DROP COLUMN OldColumnName

EXEC sp_rename 'yourTable.NewColumn', 'OldColumnName', 'COLUMN'


参数\ @objname模棱两可,或者声明的\ @objtype(COLUMN)错误。
珍妮·奥雷利

1
@ JennyO'Reilly:将它放在一个单独的问题中,然后向我们展示您正在使用的完整命令!
marc_s

2
失败的是sp_rename过程。我通过搜索错误文本找到了关于stackoverflow的解决方案。尽管我的表名称中没有任何特殊字符,但这似乎是一些带有括号的严格语法规则。
珍妮·奥莱利

1
或可能像是:'ALTER TABLE(yourTable)DROP COLUMN OldColumnName'和'ALTER TABLE(yourTable)ADD OldColumnName INT IDENTITY(1,1)',为什么要重命名:p
RK Sharma

Marc,我在一个巨大的表(约3亿行)上尝试了此确切命令,但我在约10分钟后停止了该过程
Naomi

14

这里描述了一个很酷的解决方案: SQL SERVER –在列上添加或删除标识属性

简而言之,在SQL Manager中手动编辑表,切换标识,不要保存更改,只显示将为更改创建的脚本,将其复制并在以后使用。

它节省了大量时间,因为它(脚本)包含与您更改的表相关的所有外键,索引等。手动编写此...上帝禁止。


这是我使用的解决方案-SSMS生成T-SQL进行更改...它是通过创建具有相同架构设计的新临时表,然后将所有行复制到其中,删除原始文件并重命名来实现的。可能需要一点时间才能完全运行,但效果很好。
mdelvecchio 2014年

我不认为Pinal Dave实际上是在说您需要运行生成的脚本,而只是为了说明通过UI进行更改对您有什么帮助……
Zack

在记录分区表时,SSMS中的这种脚本功能(更改表的定义)实际上是唯一正确的工具。最合适的位置“任务”->“脚本表”总是忘记编写分区功能脚本!
Martijn van der Jagt

1
可能对某人有帮助。更改后获取更改脚本。在SSMS上的设计模式下右键单击该表,然后选择选项“ Generate Change Script”,然后将脚本保存在本地驱动器中
Vijai


6

简单的解释

使用sp_RENAME重命名现有列

EXEC sp_RENAME'Table_Name.Existing_ColumnName','New_ColumnName','COLUMN'

重命名示例:

现有列UserID重命名为OldUserID

EXEC sp_RENAME 'AdminUsers.UserID' , 'OldUserID', 'COLUMN'

然后使用alter query添加新列以将其设置为主键和标识值

ALTER TABLE TableName ADD Old_ColumnName INT NOT NULL PRIMARY KEY IDENTITY(1,1)

设置主键示例

新创建的列名称为UserID

ALTER TABLE Users ADD UserID INT NOT NULL PRIMARY KEY IDENTITY(1,1)

然后删除重命名列

ALTER TABLE Table_Name DROP COLUMN Renamed_ColumnName

Drop重命名列的示例

ALTER TABLE Users DROP COLUMN OldUserID

现在,我们向表的现有列添加了主键和标识。


5

我是一名Java开发人员,碰巧加入了一个没有DBA的团队,而作为开发人员,我却无法获得DBA权利。我的任务是在两个数据库之间移动整个架构,因此,没有DBA,我必须通过运行脚本来做到这一点,并且不能在SQL Server 2008中使用GUI,因为我没有管理员权限。

一切都顺利进行,但是,当在新的schema.table上运行存储过程时,我发现我丢失了表中的identity字段。我仔细检查了创建表的脚本,它在那里,但是,当我运行脚本时,SQL Server没有得到它。后来,DBA告诉我他以前也遇到过同样的问题。

无论如何,对于SQL Server 2008,这些都是我为解决此问题而采取的步骤,并且它们起作用了,因此,我将其发布在此处,希望对您有所帮助。这是我做的,因为我对另一个表具有FK依赖关系,这使得此操作更加困难:

我使用此查询来验证身份确实丢失,并查看对该表的依赖关系。

1.)在表格上查找统计信息:

exec sp_help 'dbo.table_name_old';

2.)创建一个重复的,相同的新表,除了在PK字段之前添加的身份字段之外。

3.)禁用身份以移动数据。

SET IDENTITY_INSERT dbo.table_name ON 

4.)传输数据。

INSERT INTO dbo.table_name_new
(
field1, field2, etc...
)
SELECT 
field1, field2, etc...
FROM 
dbo.table_name_old;

5.)确认数据在那里。

SELECT * FROM dbo.table_name_new

6.)重新启用身份。

SET IDENTITY_INSERT ToyRecP.ToyAwards.lkpFile_New OFF

7.)这是我发现的最好的脚本,它可以获取所有FK关系,以验证原始表引用了哪些表作为依赖关系,并且遇到了很多表,因此它是管理员!

SELECT f.name AS ForeignKey,
   OBJECT_NAME(f.parent_object_id) AS TableName,
   COL_NAME(fc.parent_object_id, fc.parent_column_id) AS ColumnName,
   OBJECT_NAME (f.referenced_object_id) AS ReferenceTableName,
   COL_NAME(fc.referenced_object_id, fc.referenced_column_id) AS ReferenceColumnName
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc
   ON f.OBJECT_ID = fc.constraint_object_id
   ORDER BY ReferenceTableName;

8.)在下一步之前,请确保您具有所有涉及的表的所有PK和FK脚本。

9.)您可以右键单击每个键,然后使用SQL Server 2008对此脚本编写脚本

10.)使用以下语法从依赖关系表中删除FK:

ALTER TABLE [dbo].[table_name] DROP CONSTRAINT [Name_of_FK]

11.)删除原始表:

DROP TABLE dbo.table_name_old;

13.)接下来的步骤取决于您在步骤9中在SQL Server 2008中创建的脚本。

-将PK添加到新表。

-将FK添加到新表中。

-将FK添加回依赖表。

14.)验证一切正确和完整。我使用GUI查看表。

15.)将新表重命名为原始表名。

exec sp_RENAME '[Schema_Name.OldTableName]' , '[NewTableName]';

最后,一切正常!


4

您不能那样做,您需要添加另一列,删除原始列并重命名新列,或创建新表,将数据复制并删除旧表,然后将新表重命名为旧表表

如果在设计器中使用SSMS并将identity属性设置为ON,则这是SQL Server在后台执行的操作。因此,如果您有一个名为[user]的表,那么当您设置UserID和Identity时会发生这种情况

BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
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

GO
CREATE TABLE dbo.Tmp_User
    (
    UserID int NOT NULL IDENTITY (1, 1),
    LastName varchar(50) NOT NULL,
    FirstName varchar(50) NOT NULL,
    MiddleInitial char(1) NULL

    )  ON [PRIMARY]
GO

SET IDENTITY_INSERT dbo.Tmp_User ON
GO
IF EXISTS(SELECT * FROM dbo.[User])
 EXEC('INSERT INTO dbo.Tmp_User (UserID, LastName, FirstName, MiddleInitial)
    SELECT UserID, LastName, FirstName, MiddleInitialFROM dbo.[User] TABLOCKX')
GO
SET IDENTITY_INSERT dbo.Tmp_User OFF
GO

GO
DROP TABLE dbo.[User]
GO
EXECUTE sp_rename N'dbo.Tmp_User', N'User', 'OBJECT'
GO
ALTER TABLE dbo.[User] ADD CONSTRAINT
    PK_User PRIMARY KEY CLUSTERED 
    (
    UserID
    ) ON [PRIMARY]

GO
COMMIT

话虽如此,但有一种方法可以通过设置按位值来破解系统表以完成此操作,但是不支持该操作,我不会这样做


4

据我了解,在正常情况下,我们将创建具有主键的表,该表具有Identity属性,
因此无法重命名删除主键 约束相关联的列,因为约束规则正在验证列结构。
为此,我们必须按照以下方式处理一些步骤:
假设TableName ='Employee'ColumnName ='EmployeeId'1

.在'Employee'表中添加新列'EmployeeId_new'ALTER
TABLE雇员ADD EmployeeId_new INT IDENTITY( 1,1)

  1. 现在从“雇员”表中删除“雇员ID”列
    ALTER TABLE雇员DROP COLUMN EmployeeId

  2. 由于主键约束规则适用并验证列结构,因此将引发错误。
    * ###' 消息5074,级别16,状态1,行1对象[PK_dbo.Employee]依赖于colmn [EmployeeId]。###

  3. 因此,我们必须首先从表“ Employee”中删除“主键”约束,然后才能删除“ ALTER TABLE Employee DROP ”列
    [PK_dbo.Employee]

  4. 现在,我们可以像上一步中从ALTER TABLE Employee DROP COLUMN EmployeeId出现错误的上一步一样,从“ Employee”表中删除“ EmployeeId”

  5. 现在从表中删除了列'EmployeeId',因此我们将使用'EmployeeId'重命名新添加的新列
    'EmployeeId_new'sp_rename'Employee.EmployeeId','EmployeeId_new','COLUMN'

  6. 要以与原来相同的形式重新布置表,我们必须为“ EmployeeId”列添加主键约束
    ALTER TABLE员工添加约束[PK_dbo.Employee]主键(EmployeeId)

8. 现在,针对身份规则以及现有的主键约束修改了表“ Employee”和“ EmployeeId”


3

通过设计,没有简单的方法可以打开或关闭现有列的标识功能。唯一的干净方法是创建一个新列,使其成为标识列,或者创建一个新表并迁移数据。

如果我们使用SQL Server Management Studio摆脱“ id”列上的标识值,则将创建一个新的临时表,将数据移至该临时表,将旧表删除,并将新表重命名。

使用Management Studio进行更改,然后在设计器中单击鼠标右键,然后选择“生成更改脚本”。

您将看到这是SQL Server在后台执行的操作。


2

不幸的是,没有一个。IDENTITY属性属于表而不是列。

比较简单的方法是在GUI中执行此操作,但是,如果不能这样做,则可以进行很多工作,包括复制数据,删除列,使用标识重新添加以及将数据放回原处。

参见此处 的逐项打击帐户。


2

在对象资源管理器中右键单击表名。您将获得一些选择。点击“设计”。将为该表打开一个新选项卡。您可以在此处的“列属性”中添加身份约束。


2

修改列的标识属性:

  • 在服务器资源管理器中,右键单击具有要修改的标识属性的表,然后单击“打开表定义”。表格在表格设计器中打开。
  • 清除要更改的列的“允许为空”复选框。
  • 在“列属性”选项卡中,展开“身份规范”属性。
  • 单击“ Is Identity”子属性的网格单元,然后从下拉列表中选择“是”。
  • 在“身份种子”单元格中键入一个值。该值将分配给表的第一行。默认情况下将分配值1。

就是这样,它对我有用


2

如果您碰巧正在使用Visual Studio 2017+

  1. 在服务器对象资源管理器中,右键单击表,然后选择“查看代码”
  2. 将修饰符“ IDENTITY”添加到您的列
  3. 更新资料

这将为您完成所有工作。


是! 感谢您的建议!我的Windows 7框上没有SSMS版本,可以对生产服务器上的表进行设计更改,因为现在是2017年,我的SSMS是2014年,而2017年SSMS需要Windows 10。进入VS 2017>服务器资源管理器>与生产SQL Server建立新连接>右键单击表>“打开表定义”> Wala!
JustJohn

实际上,我发现您可以右键单击该字段,然后选择“属性”,然后在此处选择“是”或“否”来使“身份”
。– JustJohn

1

如果原始发布者实际上是想将现有列设置PRIMARY KEY为表的列,而实际上并不需要将该列成为IDENTITY列(两个不同的东西),则可以通过t-SQL使用以下方法完成:

ALTER TABLE [YourTableName]
ADD CONSTRAINT [ColumnToSetAsPrimaryKey] PRIMARY KEY ([ColumnToSetAsPrimaryKey])

请注意,该PRIMARY KEY选项后面的列名周围应加上括号。

尽管这篇文章很陈旧,并且我对请求者的需求进行了假设,但我认为这些附加信息可能会对遇到该线程的用户有所帮助,因为我认为对话可能会导致人们认为现有列不能设置为主键而不先将其添加为新列,这将是不正确的。


1

根据我目前的状况,我遵循这种方法。我想在通过脚本插入数据后为主表赋予身份。

因为我想附加身份,所以它总是从1到我想要的记录计数的结尾。

--first drop column and add with identity
ALTER TABLE dbo.tblProductPriceList drop column ID 
ALTER TABLE dbo.tblProductPriceList add ID INT IDENTITY(1,1)

--then add primary key to that column (exist option you can ignore)
IF  NOT EXISTS (SELECT * FROM sys.key_constraints  WHERE object_id = OBJECT_ID(N'[dbo].[PK_tblProductPriceList]') AND parent_object_id = OBJECT_ID(N'[dbo].[tblProductPriceList]'))
    ALTER TABLE [tblProductPriceList] ADD PRIMARY KEY (id)
GO

这将创建具有标识的相同主键列

我使用了以下链接:https : //blog.sqlauthority.com/2014/10/11/sql-server-add-auto-incremental-identity-column-to-table-after-creating-table/

将主键添加到现有表


0

我不相信您可以使用tsql将现有列更改为标识列。但是,您可以通过企业管理器设计视图来完成。

或者,您可以创建一个新行作为标识列,删除旧列,然后重命名新列。

ALTER TABLE FooTable
ADD BarColumn INT IDENTITY(1, 1)
               NOT NULL
               PRIMARY KEY CLUSTERED

2
请记住,如果通过SSMS / Enterprise Manager执行此操作,则将创建一个新表,复制数据,删除旧表并重命名新表。当您有大桌子时,那可能会非常昂贵……
Scott Ivey

0

基本上有四个逻辑步骤。

  1. 创建一个新的标识列。打开此新列的插入身份。

  2. 将数据从源列(您希望转换为身份的列)插入此新列。

  3. 关闭新列的插入标识。

  4. 删除您的源列,并将新列重命名为源列的名称。

可能会有更多复杂性,例如跨多个服务器工作等等。

请参考以下文章中的步骤(使用ssms和T-sql)。这些步骤适用于对T-SQL不太了解的初学者。

http://social.technet.microsoft.com/wiki/contents/articles/23816.how-to-con-convert-int-column-to-identity-in-the-ms-sql-server.aspx


0

为所有主键为bigint且未设置身份的表生成脚本;这将返回每个表生成的脚本的列表;

SET NOCOUNT ON;

declare @sql table(s varchar(max), id int identity)

DECLARE @table_name nvarchar(max),
        @table_schema nvarchar(max);

DECLARE vendor_cursor CURSOR FOR 
SELECT
  t.name, s.name
FROM sys.schemas AS s
INNER JOIN sys.tables AS t
  ON s.[schema_id] = t.[schema_id]
WHERE EXISTS (
    SELECT
    [c].[name]
    from sys.columns [c]
    join sys.types [y] on [y].system_type_id = [c].system_type_id
    where [c].[object_id] = [t].[object_id] and [y].name = 'bigint' and [c].[column_id] = 1
) and NOT EXISTS 
(
  SELECT 1 FROM sys.identity_columns
    WHERE [object_id] = t.[object_id]
) and exists (
    select 1 from sys.indexes as [i] 
    inner join sys.index_columns as [ic]  ON  i.OBJECT_ID = ic.OBJECT_ID AND i.index_id = ic.index_id
    where object_name([ic].[object_id]) = [t].[name]
)
OPEN vendor_cursor

FETCH NEXT FROM vendor_cursor 
INTO @table_name, @table_schema

WHILE @@FETCH_STATUS = 0
BEGIN

DELETE FROM @sql

declare @pkname varchar(100),
    @pkcol nvarchar(100)

SELECT  top 1
        @pkname = i.name,
        @pkcol = COL_NAME(ic.OBJECT_ID,ic.column_id)
FROM    sys.indexes AS [i]
INNER JOIN sys.index_columns AS [ic] ON  i.OBJECT_ID = ic.OBJECT_ID AND i.index_id = ic.index_id
WHERE   i.is_primary_key = 1 and OBJECT_NAME(ic.OBJECT_ID) = @table_name

declare @q nvarchar(max) = 'SELECT  '+@pkcol+' FROM ['+@table_schema+'].['+@table_name+'] ORDER BY '+@pkcol+' DESC'

DECLARE @ident_seed nvarchar(max) -- Change this to the datatype that you are after
SET @q = REPLACE(@q, 'SELECT', 'SELECT TOP 1 @output = ')
EXEC sp_executeSql @q, N'@output bigint OUTPUT', @ident_seed OUTPUT

insert into  @sql(s) values ('BEGIN TRANSACTION')
insert into  @sql(s) values ('BEGIN TRY')

-- create statement
insert into  @sql(s) values ('create table ['+@table_schema+'].[' + @table_name + '_Temp] (')

-- column list
insert into @sql(s) 
select 
    '  ['+[c].[name]+'] ' +
    y.name + 

    (case when [y].[name] like '%varchar' then
    coalesce('('+(case when ([c].[max_length] < 0 or [c].[max_length] >= 1024) then 'max' else cast([c].max_length as varchar) end)+')','')
    else '' end)

     + ' ' +
    case when [c].name = @pkcol then 'IDENTITY(' +COALESCE(@ident_seed, '1')+',1)' else '' end + ' ' +
    ( case when c.is_nullable = 0 then 'NOT ' else '' end ) + 'NULL ' + 
    coalesce('DEFAULT ('+(
        REPLACE(
            REPLACE(
                LTrim(
                    RTrim(
                        REPLACE(
                            REPLACE(
                                REPLACE(
                                    REPLACE(
                                        LTrim(
                                            RTrim(
                                                REPLACE(
                                                    REPLACE(
                                                        object_definition([c].default_object_id)
                                                    ,' ','~')
                                                ,')',' ')
                                            )
                                        )
                                    ,' ','*')
                                ,'~',' ')
                            ,' ','~')
                        ,'(',' ')
                    )
                )
            ,' ','*')
        ,'~',' ')
    ) +
    case when object_definition([c].default_object_id) like '%get%date%' then '()' else '' end
    +
    ')','') + ','
 from sys.columns c
 JOIN sys.types y ON y.system_type_id = c.system_type_id
  where OBJECT_NAME(c.[object_id]) = @table_name and [y].name != 'sysname'
 order by [c].column_id


 update @sql set s=left(s,len(s)-1) where id=@@identity

-- closing bracket
insert into @sql(s) values( ')' )

insert into @sql(s) values( 'SET IDENTITY_INSERT ['+@table_schema+'].['+@table_name+'_Temp] ON')

declare @cols nvarchar(max)
SELECT @cols = STUFF(
    (
        select ',['+c.name+']'
        from sys.columns c
        JOIN sys.types y ON y.system_type_id = c.system_type_id
        where c.[object_id] = OBJECT_ID(@table_name)
        and [y].name != 'sysname'
        and [y].name != 'timestamp'
        order by [c].column_id
        FOR XML PATH ('')
     )
    , 1, 1, '')

insert into @sql(s) values( 'IF EXISTS(SELECT * FROM ['+@table_schema+'].['+@table_name+'])')
insert into @sql(s) values( 'EXEC(''INSERT INTO ['+@table_schema+'].['+@table_name+'_Temp] ('+@cols+')')
insert into @sql(s) values( 'SELECT '+@cols+' FROM ['+@table_schema+'].['+@table_name+']'')')

insert into @sql(s) values( 'SET IDENTITY_INSERT ['+@table_schema+'].['+@table_name+'_Temp] OFF')


insert into @sql(s) values( 'DROP TABLE ['+@table_schema+'].['+@table_name+']')

insert into @sql(s) values( 'EXECUTE sp_rename N''['+@table_schema+'].['+@table_name+'_Temp]'', N'''+@table_name+''', ''OBJECT''')

if ( @pkname is not null ) begin
    insert into @sql(s) values('ALTER TABLE ['+@table_schema+'].['+@table_name+'] ADD CONSTRAINT ['+@pkname+'] PRIMARY KEY CLUSTERED (')
    insert into @sql(s)
        select '  ['+COLUMN_NAME+'] ASC,' from information_schema.key_column_usage
        where constraint_name = @pkname
        GROUP BY COLUMN_NAME, ordinal_position
        order by ordinal_position

    -- remove trailing comma
    update @sql set s=left(s,len(s)-1) where id=@@identity
    insert into @sql(s) values ('  )')
end

insert into  @sql(s) values ('--Run your Statements')
insert into  @sql(s) values ('COMMIT TRANSACTION')
insert into  @sql(s) values ('END TRY')
insert into  @sql(s) values ('BEGIN CATCH')
insert into  @sql(s) values ('        ROLLBACK TRANSACTION')
insert into  @sql(s) values ('        DECLARE @Msg NVARCHAR(MAX)  ')
insert into  @sql(s) values ('        SELECT @Msg=ERROR_MESSAGE() ')
insert into  @sql(s) values ('        RAISERROR(''Error Occured: %s'', 20, 101,@msg) WITH LOG')
insert into  @sql(s) values ('END CATCH')

declare @fqry nvarchar(max)

-- result!
SELECT @fqry = (select char(10) + s from @sql order by id FOR XML PATH (''))


SELECT @table_name as [Table_Name], @fqry as [Generated_Query]
PRINT 'Table: '+@table_name
EXEC sp_executeSql @fqry

    FETCH NEXT FROM vendor_cursor 
    INTO @table_name, @table_schema
END 
CLOSE vendor_cursor;
DEALLOCATE vendor_cursor;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.