关于sql:向现有列添加标识

Adding an identity to an existing column

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

我有一个脚本来清理ID以确保它们从1开始顺序启动,在我的测试数据库上运行正常。

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


您无法更改现有列的标识。

你有2个选择,

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

  • 使用标识创建新列并删除现有列

  • 方法1.(新表)您可以在此处保留新创建的标识列上的现有数据值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    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(新列)您无法在新创建的标识列上保留现有数据值,标识列将保留数字序列。

    1
    2
    3
    4
    5
    6
    7
    8
    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)


    在SQL 2005及更高版本中,可以在不更改表的数据页的情况下解决此问题。这对于触摸每个数据页可能需要几分钟或几小时的大型表非常重要。即使标识列是主键,是集群或非集群索引的一部分,或者其他陷阱可以使更简单的"添加/删除/重命名列"解决方案绊倒,这个技巧也有效。

    下面是技巧:您可以使用SQL Server的ALTER TABLE ... SWITCH语句来更改表的模式而不更改数据,这意味着您可以使用具有相同表模式但没有IDENTITY列的IDENTITY替换表。同样的技巧可以将IDENTITY添加到现有列。

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

    我用这个技巧在5秒内将IDENTITY中25亿行表中的一列转换为非IDENTITY(为了运行一个多小时查询,其查询计划更适合非IDENTITY列),然后在不到5秒的时间内恢复IDENTITY设置。

    这是一个如何工作的代码示例。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     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;

    这显然比其他答案中的解决方案更复杂,但如果你的桌子很大,这可以真正节省生命。有一些警告:

    • 据我所知,使用此方法,您可以使用此方法更改有关表格列的唯一信息。不允许添加/删除列,更改可为空性等。
    • 在进行切换之前,您需要删除foriegn密钥并在之后恢复它们。
    • 对于WITH SCHEMABINDING函数,视图等也是如此
    • 新表的索引需要完全匹配(相同的列,相同的顺序等)
    • 旧表和新表需要位于同一文件组中。
    • 仅适用于SQL Server 2005或更高版本
    • 我以前认为这个技巧只适用于SQL Server的企业版或开发者版(因为分区仅在Enterprise和Developer版本中支持),但Mason G. Zhwiti在下面的评论中说它也适用于SQL标准版。我认为这意味着对Enterprise或Developer的限制不适用于ALTER TABLE ... SWITCH。

    TechNet上有一篇很好的文章详细说明了上述要求。

    更新 - Eric Wu在下面发表评论,增加了有关此解决方案的重要信息。在此处复制以确保它得到更多关注:

    There's another caveat here that is worth mentioning. Althought the
    new table will happily receive data from the old table, and all the
    new rows will be inserted following a identity pattern, they will
    start at 1 and potentially break if the said column is a primary key.
    Consider running DBCC CHECKIDENT('') immediately after
    switching. See msdn.microsoft.com/en-us/library/ms176057.aspx for more
    info.

    如果使用新行主动扩展表(意味着在添加IDENTITY和添加新行之间没有太多停机时间,那么您需要在新表中手动设置标识种子值,而不是DBCC CHECKIDENT模式大于表中最大的现有ID,例如IDENTITY (2435457, 1)。您可能能够在事务中包含ALTER TABLE...SWITCHDBCC CHECKIDENT(或者没有 - 没有测试过这个)但似乎比如手动设置种子值会更容易和更安全。

    显然,如果没有新的行添加到表中(或者它们只是偶尔添加,就像每日ETL过程一样),那么这种竞争条件就不会发生,所以DBCC CHECKIDENT没问题。


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

    1
    2
    3
    4
    5
    ALTER TABLE (yourTable) ADD NewColumn INT IDENTITY(1,1)

    ALTER TABLE (yourTable) DROP COLUMN OldColumnName

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


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

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

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


    考虑使用SEQUENCE而不是IDENTITY。

    在SQL Server 2014(我不知道更低版本)你可以使用序列简单地做到这一点。

    1
    2
    3
    CREATE SEQUENCE  sequence_name START WITH here_higher_number_than_max_existed_value_in_column INCREMENT BY 1;

    ALTER TABLE TABLE_NAME ADD CONSTRAINT constraint_name DEFAULT NEXT VALUE FOR sequence_name FOR column_name

    从此处:序列作为列的默认值


    简单的解释

    使用sp_RENAME重命名现有列

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

    重命名示例:

    现有列UserID重命名为OldUserID

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

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

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

    设置主键的示例

    新创建的列名称是UserID

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

    然后删除重命名列

    1
    ALTER TABLE TABLE_NAME DROP COLUMN Renamed_ColumnName

    Drop重命名列的示例

    1
    ALTER TABLE Users DROP COLUMN OldUserID

    现在我们将主键和标识添加到表中的现有列。


    我是一名java开发人员,碰巧遇到没有DBA的团队,而且作为开发人员,我无法获得DBA权利。我的任务是在两个数据库之间移动整个模式,所以没有DBA,我必须通过运行脚本来完成它,而不能在SQL Server 2008中使用GUI,因为我没有管理员权限。

    一切都没有问题,但是,当在新的schema.table上运行存储过程时,我发现我丢失了表中的标识字段。我仔细检查了创建表的脚本,但是,当我运行脚本时,SQL Server没有得到它。后来我被DBA告知他之前见过同样的问题。

    无论如何,对于SQL Server 2008,这些是我为解决这个问题而采取的步骤,所以我在这里发布了这个,希望它能帮到某个人。这就是我所做的,因为我在另一个表上有FK依赖,这使得这更难:

    我使用此查询来验证确实缺少身份并查看表上的依赖项。

    1.)查找表格的统计数据:

    1
    EXEC sp_help 'dbo.table_name_old';

    2.)创建一个重复的,相同的新表,除了在PK字段上添加标识字段之前的位置。

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

    1
    SET IDENTITY_INSERT dbo.table_name ON

    4.)传输数据。

    1
    2
    3
    4
    5
    6
    7
    8
    INSERT INTO dbo.table_name_new
    (
    field1, field2, etc...
    )
    SELECT
    field1, field2, etc...
    FROM
    dbo.table_name_old;

    5.)验证数据是否存在。

    1
    SELECT * FROM dbo.table_name_new

    6.)重新启用身份。

    1
    SET IDENTITY_INSERT ToyRecP.ToyAwards.lkpFile_New OFF

    7.)这是我发现的最好的脚本,它可以获得所有FK关系,以验证原始表引用哪些表作为依赖项
    我遇到了很多,所以它是守门员!

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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:

    1
    ALTER TABLE [dbo].[TABLE_NAME] DROP CONSTRAINT [Name_of_FK]

    11.)删除原始表:

    1
    DROP TABLE dbo.table_name_old;

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

    - 将PK添加到新表中。

    - 将FK添加到新表中。

    - 将FK添加回依赖关系表。

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

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

    1
    EXEC sp_RENAME '[Schema_Name.OldTableName]' , '[NewTableName]';

    最后,一切正常!


    正如我在正常情况下所理解的那样,我们正在创建一个具有主键的表,该主键具有标识属性
    因此,由于约束规则正在验证列结构,因此无法重命名或删除与主键约束关联的列
    要实现这一点,我们必须以下列方式处理一些步骤:
    我们假设TableName ='Employee'和ColumnName ='EmployeeId'




    1.在"员工"表中添加新列"EmployeeId_new"


    ALTER TABLE员工ADD EmployeeId_new INT IDENTITY(1,1)

  • 现在从'Employee'表中删除列'EmployeeId'


    ALTER TABLE Employee DROP COLUMN EmployeeId

  • 由于主键约束规则适用并验证列结构,因此会抛出错误。


    * ###
    '消息5074,级别16,状态1,行1对象[PK_dbo.Employee]依赖于colmn [EmployeeId]。'###

  • 因此,我们必须首先从表'Employee'中删除主键约束,然后我们可以删除该列


    ALTER TABLE员工DROP约束[PK_dbo.Employee]

  • 现在我们可以从'Employee'表中删除"EmployeeId"列,就像我们收到错误的上一步一样


    ALTER TABLE Employee DROP COLUMN EmployeeId

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


    sp_rename'Employee.EmployeeId','EmployeeId_new','COLUMN'

  • 要以与原来相同的形式重新排列表格,我们必须为"EmployeeId"列添加主键约束


    ALTER TABLE员工添加约束[PK_dbo.Employee]主键(EmployeeId)

  • 8.现在,使用'EmployeeId'表'Employee'被修改为Identity规则以及现有的主键约束


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

    如果我们使用SQL Server Management Studio来删除列"id"上的标识值,则会创建一个新的临时表,将数据移动到临时表,删除旧表并重命名新表。

    使用Management Studio进行更改,然后右键单击设计器并选择"生成更改脚本"。

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


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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    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

    已经说过有一种方法可以通过设置按位值来破解系统表来实现它,但这是不支持的,我不会这样做


    要修改列的标识属性:

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

    就是这样,它对我有用


    右键单击对象资源管理器中的表名称。你会得到一些选择。点击"设计"。将为此表打开一个新选项卡。您可以在"列属性"中添加标识约束。


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

    更简单的方法是在GUI中执行此操作,但如果这不是一个选项,您可以大大复制数据,删除列,重新添加标识,然后重新放回数据。

    在这里查看逐个帐户。


    如果您碰巧使用Visual Studio 2017+

  • 在Server Object Explorer中右键单击表并选择"view code"
  • 将修饰符"IDENTITY"添加到列中
  • 更新
  • 这将为您完成所有这一切。


    如果原始海报实际上想要将现有列设置为表的PRIMARY KEY并且实际上不需要该列是IDENTITY列(两个不同的东西),那么这可以通过t-SQL来完成:

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

    请注意PRIMARY KEY选项后列名称周围的括号。

    虽然这篇文章很老,我正在对请求者的需求做出假设,但我觉得这些额外的信息可能会对遇到这个帖子的用户有所帮助,因为我相信这个对话可能会导致人们相信现有的列不能被设置为主键不首先将其添加为新列,这将是不正确的。


    根据我目前的情况,我遵循这种方法。我希望在通过脚本插入数据后为主表提供标识。

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

    1
    2
    3
    4
    5
    6
    7
    8
    --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/

    将主键添加到现有表


    为主键= bigint的所有表生成一个脚本,该脚本没有标识集;这将返回每个表生成的脚本列表;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    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;

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

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

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


    基本上有四个逻辑步骤。

  • 创建一个新的Identity列。为此新列启用"插入标识"。

  • 将源列(您希望转换为Identity的列)中的数据插入此新列。

  • 关闭新列的"插入标识"。

  • 删除源列并将新列重命名为源列的名称。

  • 可能存在一些更复杂的问题,例如跨多个服务器等工作。

    请参阅以下文章了解步骤(使用ssms和T-sql)。这些步骤适用于对T-SQL较少掌握的初学者。

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