用脚本编写所有外键的删除和创建

时间:2018-07-11 07:13:27

标签: sql sql-server foreign-keys

我需要从数据库中整理事务数据,仅保留主数据。从历史上看,这是通过SP以特定顺序从表中删除来完成的,但是由于数据库大小达到半terrabyte,所以速度太慢。

因此,我想到了删除键,截断表和恢复键的想法,并且在大多数情况下,这种方法很奏效,但我发现了一个错误,无法解决。

问题是,具有删除级联的外键将恢复,但没有删除级联,这给应用程序带来了问题,并使我的进程不可用:(

任何人都可以看到缺少的功能吗?还是我在这里可能还会想念的其他东西?

SET NOCOUNT ON

create table #fixes
(TableName nvarchar(200)
,Fix nvarchar(max)
,[type] nvarchar(10))

Insert into #fixes

Select KCU1.TABLE_SCHEMA COLLATE DATABASE_DEFAULT + '.' + KCU1.TABLE_NAME COLLATE DATABASE_DEFAULT 
,

'

IF (OBJECT_ID(''' + rc.CONSTRAINT_NAME + ''', ''F'') IS NOT NULL) OR (OBJECT_ID(''DSDBA.' + rc.CONSTRAINT_NAME + ''', ''F'') IS NOT NULL) 
BEGIN
 ALTER TABLE ' + QUOTENAME(RC.CONSTRAINT_SCHEMA)
    + '.' + QUOTENAME(KCU1.TABLE_NAME)
    + ' DROP CONSTRAINT ' + QUOTENAME(rc.CONSTRAINT_NAME) +

'END; 
'
,'DROP'

FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU1
    ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG
    AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA
    AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME
WHERE ORDINAL_POSITION=1

Insert into #fixes

Select
cs.name COLLATE DATABASE_DEFAULT + '.' + ct.name COLLATE DATABASE_DEFAULT 
 ,
'
IF (OBJECT_ID(''' + fk.NAME + ''', ''F'') IS NULL) OR (OBJECT_ID(''DSDBA.' + fk.name + ''', ''F'') IS NULL) 
BEGIN
ALTER TABLE ' 
   + QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name) 
   + ' ADD CONSTRAINT ' + QUOTENAME(fk.name) 
   + ' FOREIGN KEY (' + STUFF((SELECT ',' + QUOTENAME(c.name)
 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'') + ')
    END
    ;'
    , 'ADD'
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





DECLARE @drops VARCHAR(max) 
SELECT @drops = COALESCE(@drops + ' ', '') + Fix
FROM #fixes f
where [type] = 'DROP'


DECLARE @adds VARCHAR(max) 
SELECT @adds = COALESCE(@adds + ' ', '') + Fix
FROM #fixes f
where [type] = 'ADD'





exec (@drops)
RAISERROR( 'Completed Dropping Keys',0,1) WITH NOWAIT

exec [DSDBA].[usp_utl_TruncateAllTransactions]
RAISERROR( 'Completed Truncating Tables',0,1) WITH NOWAIT

exec (@adds)
RAISERROR( 'Completed Reinstating Keys',0,1) WITH NOWAIT



drop table #fixes

谢谢, D

1 个答案:

答案 0 :(得分:0)

所以问题是我只需要处理sys.foreign_keys上的标志。出于我的目的,我们仅使用删除级联,但是为了其他发现这篇文章的人的利益,我包括了其他删除和更新操作的处理

SET NOCOUNT ON

create table #fixes
(TableName nvarchar(200)
,Fix nvarchar(max)
,[type] nvarchar(10))

Insert into #fixes

Select KCU1.TABLE_SCHEMA COLLATE DATABASE_DEFAULT + '.' + KCU1.TABLE_NAME COLLATE DATABASE_DEFAULT 
,

'

IF (OBJECT_ID(''' + rc.CONSTRAINT_NAME + ''', ''F'') IS NOT NULL) OR (OBJECT_ID(''DSDBA.' + rc.CONSTRAINT_NAME + ''', ''F'') IS NOT NULL) 
BEGIN
 ALTER TABLE ' + QUOTENAME(RC.CONSTRAINT_SCHEMA)
    + '.' + QUOTENAME(KCU1.TABLE_NAME)
    + ' DROP CONSTRAINT ' + QUOTENAME(rc.CONSTRAINT_NAME) +

'END; 
'
,'DROP'

FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU1
    ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG
    AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA
    AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME
WHERE ORDINAL_POSITION=1

Insert into #fixes

Select
cs.name COLLATE DATABASE_DEFAULT + '.' + ct.name COLLATE DATABASE_DEFAULT 
 ,
'
IF (OBJECT_ID(''' + fk.NAME + ''', ''F'') IS NULL) OR (OBJECT_ID(''DSDBA.' + fk.name + ''', ''F'') IS NULL) 
BEGIN
ALTER TABLE ' 
   + QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name) 
   + ' ADD CONSTRAINT ' + QUOTENAME(fk.name) 
   + ' FOREIGN KEY (' + STUFF((SELECT ',' + QUOTENAME(c.name)
 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'') + ')
    '

    /** BEGIN SOLUTION **//
    +
    case objectproperty(fk.object_id, 'CnstDeleteAction') when 0 then '' when 1 then 'ON DELETE CASCADE' when 2 then 'ON DELETE SET NULL' when 3 then 'ON DELETE SET DEFAULT' end
    +
    case objectproperty(fk.object_id, 'CnstUpdateAction') when 0 then '' when 1 then 'ON UPDATE CASCADE' when 2 then 'ON UPDATE SET NULL' when 3 then 'ON UPDATE SET NULL' end
    +
    /** END SOLUTION **//

    '
    END
    ;'
    , 'ADD'
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





DECLARE @drops VARCHAR(max) 
SELECT @drops = COALESCE(@drops + ' ', '') + Fix
FROM #fixes f
where [type] = 'DROP'


DECLARE @adds VARCHAR(max) 
SELECT @adds = COALESCE(@adds + ' ', '') + Fix
FROM #fixes f
where [type] = 'ADD'




Select * from #fixes
--drop table #fixes