删除多个表的外键上的ON DELETE CASCADE

时间:2018-06-17 12:47:14

标签: sql-server tsql

我有几个带有外键约束的表,其中包含ON DELETE CASCADE选项。每个表都属于名为datasets的相同模式。

我可以使用以下方法检索完整的表列表:

SELECT * 
FROM INFORMATION_SCHEMA.TABLES 
WHERE TABLE_SCHEMA ='datasets'

对于每个表,我想删除名为ON DELETE CASCADE的外键约束上的FK_[TABLENAME]_SerieID选项,其中[TABLENAME]对应于表的名称(SerieId是跨表的相同外键)。

我可以使用以下方法对特定表执行操作,例如名为Table1的表:

ALTER TABLE  datasets.Table1
    DROP CONSTRAINT FK_Table1_SerieID

ALTER TABLE datasets.Table1
    ADD CONSTRAINT FK_Table1_SerieID
        FOREIGN KEY (Serie_Id) REFERENCES[dbo].[Serie](SerieID)
        ON DELETE NO ACTION
GO

我想对属于架构datasets的每个表执行上述操作。我是T-SQL的新手,我不知道该怎么做。

我应该使用光标吗?你能帮我解决这个问题吗?

我正在使用SQL Server 2016。

1 个答案:

答案 0 :(得分:1)

我不会重新发明轮子。有很好的剧本由 Aaron Bertrand: Drop and Re-Create All Foreign Key Constraints in SQL Server 撰写。

您可以通过添加简单的NO ACTION限制来轻松扩展它以处理WHERE案例和特定架构:

DECLARE @drop   NVARCHAR(MAX) = N'',
        @create NVARCHAR(MAX) = N'';

-- drop is easy,just build a simple concatenated list from sys.foreign_keys:
SELECT @drop += N'
ALTER TABLE ' + QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name) 
    + ' DROP CONSTRAINT ' + QUOTENAME(fk.name) + ';'
FROM sys.foreign_keys AS fk
INNER JOIN sys.tables AS ct
  ON fk.parent_object_id = ct.[object_id]
INNER JOIN sys.schemas AS cs 
  ON ct.[schema_id] = cs.[schema_id]
WHERE delete_referential_action_desc <> 'NO_ACTION'  -- here 
    AND cs.name = 'datasets';

-- create is a little more complex. We need to generate the list of 
-- columns on both sides of the constraint, even though in most cases
-- there is only one column.
SELECT @create += N'
ALTER TABLE ' 
   + QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name) 
   + ' ADD CONSTRAINT ' + QUOTENAME(fk.name) 
   + ' FOREIGN KEY (' + STUFF((SELECT ',' + QUOTENAME(c.name)
   -- get all the columns in the constraint table
    FROM sys.columns AS c 
    INNER JOIN sys.foreign_key_columns AS fkc 
    ON fkc.parent_column_id = c.column_id
    AND fkc.parent_object_id = c.[object_id]
    WHERE fkc.constraint_object_id = fk.[object_id]
    ORDER BY fkc.constraint_column_id 
    FOR XML PATH(N''), TYPE).value(N'.[1]', N'nvarchar(max)'),1,1,N'')
  + ') REFERENCES ' + QUOTENAME(rs.name) + '.' + QUOTENAME(rt.name)
  + '(' + STUFF((SELECT ',' + QUOTENAME(c.name)
   -- get all the referenced columns
    FROM sys.columns AS c 
    INNER JOIN sys.foreign_key_columns AS fkc 
    ON fkc.referenced_column_id = c.column_id
    AND fkc.referenced_object_id = c.[object_id]
    WHERE fkc.constraint_object_id = fk.[object_id]
    ORDER BY fkc.constraint_column_id 
    FOR XML PATH(N''), TYPE).value(N'.[1]', N'nvarchar(max)'),1,1,N'') + ');'
FROM sys.foreign_keys AS fk
INNER JOIN sys.tables AS rt -- referenced table
  ON fk.referenced_object_id = rt.[object_id]
INNER JOIN sys.schemas AS rs 
  ON rt.[schema_id] = rs.[schema_id]
INNER JOIN sys.tables AS ct -- constraint table
  ON fk.parent_object_id = ct.[object_id]
INNER JOIN sys.schemas AS cs 
  ON ct.[schema_id] = cs.[schema_id]
WHERE rt.is_ms_shipped = 0 AND ct.is_ms_shipped = 0
  AND delete_referential_action_desc <> 'NO_ACTION' -- here
  AND cs.name = 'datasets';
print(@drop);
print(@create);
-- ...

<强> DBFiddle Demo

一个警告!请避免添加ORDER BY

此脚本使用

SELECT @drop += N'...'
<=>
SELECT @drop = @drop + N'...'

它可能会开始产生不正确的结果。更多nvarchar concatenation / index / nvarchar(max) inexplicable behavior