将自动增量添加到列并处理约束[SQL Server]

时间:2017-05-03 08:49:42

标签: sql sql-server

我需要将autoincrement(IDENTITY)属性添加到某些表的ID列。我做过一些研究表明我需要先删除ID列,然后再将它们添加为IDENTITY列。但是,当我尝试删除ID列时,我得到一个错误消息列表,主要是说:

-The object 'FK_OTHER_TABLE_MY_ID' is dependent on column 'MY_ID'. (foreign key constraint apparently)

-The object 'IDX_PK_MY_TABLE' is dependent on column 'my_ID' (Primary key constraint).

所以我可以删除约束(外键在我的表中的其他表和主键中),然后再次添加它们。

如果是这样,是否有一种方法可以在引用我的ID列时为所有外键执行此操作,这种方法比只丢失错误消息中定义的约束更容易出错。

2 个答案:

答案 0 :(得分:0)

在执行使标识列工作所需的操作之前,您需要先删除引用的外键。

答案 1 :(得分:0)

您可以使用sp_fkeys根据表格查找所有外键;

EXEC sp_fkeys 'TableName'

如果你想要一个脚本,那么你可以做这样的动态。中间有一个部分,您可以将脚本改为IDENTITY字段;

DECLARE @PKTableName VARCHAR(100), 
        @PKName varchar(100),
        @FKName varchar(100),
        @sql varchar(max),
        @PKcolumnName varchar(30),
        @FKtable VARCHAR(100),
        @FKColumnName VARCHAR(100), 
        @parentColumnNumber int

SET @PKTableName = 'YourTableName'

IF OBJECT_ID('tempdb..#FKAgainstTableList') IS NOT NULL 
    DROP TABLE #FKAgainstTableList
CREATE TABLE #FKAgainstTableList (FKTable varchar(100), FKName varchar(100), FKColumnName varchar(100))

IF OBJECT_ID('tempdb..#PKDetails') IS NOT NULL 
    DROP TABLE #PKDetails
CREATE TABLE #PKDetails (PKName varchar(100), PKColumnName varchar(100), Ordinal_Position int)

/* Let's gather details about our primary key */
INSERT INTO #PKDetails (PKName, PKColumnName, Ordinal_Position)
SELECT
     CONSTRAINT_NAME 
    ,COLUMN_NAME 
    ,ORDINAL_POSITION 
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE 
WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1 
    AND table_name = @PKTableName

/* We need this when we're putting the FK's back on at the end */
SET @PKName = (SELECT DISTINCT PKName FROM #PKDetails)
SELECT @PKcolumnName = COALESCE(@PKcolumnName + ' ASC,', '') + PKColumnName FROM #PKDetails ORDER BY ORDINAL_POSITION ASC

/* Let's grab the foreign keys and put them into a temp table */
INSERT INTO #FKAgainstTableList (FKTable, FKName, FKColumnName)
SELECT DISTINCT
     KC.TABLE_NAME 
    ,KC.CONSTRAINT_NAME 
    ,STUFF((SELECT ',' + KCU.COLUMN_NAME 
            FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU
            JOIN sys.foreign_keys FK ON KCU.CONSTRAINT_NAME = FK.name
            WHERE OBJECT_NAME(fk.referenced_object_id) = @PKTableName AND KCU.CONSTRAINT_NAME = KC.CONSTRAINT_NAME
            ORDER BY ORDINAL_POSITION ASC
            FOR XML PATH('')
            ),1,1,'') 
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE KC
WHERE STUFF((SELECT ',' + KCU.COLUMN_NAME 
            FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU
            JOIN sys.foreign_keys FK ON KCU.CONSTRAINT_NAME = FK.name
            WHERE OBJECT_NAME(fk.referenced_object_id) = @PKTableName AND KCU.CONSTRAINT_NAME = KC.CONSTRAINT_NAME
            ORDER BY ORDINAL_POSITION ASC
            FOR XML PATH('')
            ),1,1,'') IS NOT NULL

/* Disable constraint on FK Tables */
DECLARE cursor1 CURSOR  FOR
    SELECT * FROM #FKAgainstTableList

    PRINT @sql

OPEN cursor1
FETCH NEXT FROM cursor1 INTO @FKtable,@FKName,@FKColumnName
WHILE   @@FETCH_STATUS = 0
    BEGIN
        SET @sql ='ALTER TABLE '+@FKtable+' DROP CONSTRAINT '+ @FKName
        PRINT @sql
        --EXEC(@sql)
        FETCH NEXT FROM cursor1 INTO @FKtable,@FKName,@FKColumnName
    END
CLOSE cursor1
DEALLOCATE cursor1


/* Let's drop that PK */
IF  EXISTS (SELECT 1 FROM sys.indexes WHERE object_id = OBJECT_ID(@PKTableName) AND name = @PKName)
BEGIN
    SET @sql = 'ALTER TABLE '+@PKTableName+' DROP CONSTRAINT '+ @PKName
    PRINT @sql
    --EXEC(@sql)

END

/* Put your script here to drop and create the IDENTITY field */


/* OK, let's apply that PK (clustered) */
SET @sql = 'ALTER TABLE '+@PKTableName +' ADD  CONSTRAINT '+@PKName+' PRIMARY KEY CLUSTERED ('+@PKcolumnName+' ASC)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 100) ON [PRIMARY]'
PRINT(@sql)
--EXEC(@sql)

/* Put the FK's back on */
DECLARE cursor2 CURSOR  FOR
    SELECT  * FROM #FKAgainstTableList
OPEN cursor2
FETCH NEXT FROM cursor2 INTO @FKtable,@FKName,@FKColumnName
WHILE   @@FETCH_STATUS = 0
    BEGIN
        SET @sql = 'ALTER TABLE '+@FKtable+' WITH CHECK ADD CONSTRAINT '+ @FKName+' FOREIGN KEY(['+REPLACE(@FKColumnName,',','],[')+'])
        REFERENCES ['+@PKTableName+'] (['+REPLACE(@PKcolumnName,' ASC,','],[')+'])'
        PRINT(@sql)
        --EXEC(@sql)

        FETCH NEXT FROM cursor2 INTO @FKtable,@FKName,@FKColumnName
    END
CLOSE cursor2
DEALLOCATE cursor2


/* Tidy up */
DROP TABLE #FKAgainstTableList
DROP TABLE #PKDetails

请注意,我已经将此脚本用于将非群集PK转换为群集PK所需的一些工作,并且原始代码已从各种来源获取并根据我的需要进行修改。我不能赞同所有这些代码。

我还注释掉了代码的执行情况,以便您可以在SSMS的消息标签中查看它将要执行的操作。