触发从主键包含表中自动删除

时间:2018-11-17 06:15:52

标签: sql-server tsql

如果外键表中不存在数据,我想从主键表中删除数据。几乎有25个子表。

1 个答案:

答案 0 :(得分:0)

首先,这不应该是触发器。触发特定动作的触发器,例如插入记录。如果要通过删除未由任何子表引用的记录来“清理”表,则这是按需执行的手动操作。因此,我们只生成一个查询,该查询将检查所有子表。

我们可以使用sys.foreign_keys表找到哪些子表。然后,我们将构造一个查询,并在where子句中为引用主表的每个子表放置and not exists语句。由于盲目删除记录会有些危险,因此我建议您首先生成SELECT语句,然后查看将要删除的行。如果一切看起来不错,您可以生成实际的DELETE语句并执行它。

生成的查询将打印在SSMS的“消息”选项卡中,您可以将其复制/粘贴到查询窗口中以执行该查询。但是,如果需要,您可以在构建后立即将其作为动态SQL执行。

完整的解决方案应如下所示:

-- The name of the table, from which you want to delete rows
declare @TableName sysname = N'dbo.USERS'

declare @SqlStatement nvarchar(max)

-- Deleting is dangerous. First execute select statement and review the rows. Then uncomment the line bellow to generate delete statement
set @SqlStatement = N'select * from ' + @TableName + ' where 1=1'
--set @SqlStatement = N'delete from ' + @TableName + ' where 1=1'

-- Returns a list of foreign keys in your database
;with cteForeignKeys as (
select
    SCHEMA_NAME(po.schema_id) + '.' + po.name as ChildTableName
    , pc.name as ChildColumnName
    , SCHEMA_NAME(ro.schema_id) + '.' + ro.name as ReferencedTableName
    , rc.name as ReferencedColumnName
    , fk.referenced_object_id
from sys.foreign_keys fk
inner join sys.foreign_key_columns fkc on fkc.constraint_object_id = fk.object_id
inner join sys.objects po on po.object_id = fkc.parent_object_id
inner join sys.columns pc on pc.object_id = fkc.parent_object_id and pc.column_id = fkc.parent_column_id
inner join sys.objects ro on ro.object_id = fkc.referenced_object_id
inner join sys.columns rc on rc.object_id = fkc.referenced_object_id and rc.column_id = fkc.referenced_column_id
)

-- Construct the where clauses for checking all child tables
select
    @SqlStatement += FORMATMESSAGE('
        and not exists(select * from %s where %s.%s = %s.%s)',
        ChildTableName, ChildTableName, ChildColumnName, 
        ReferencedTableName, ReferencedColumnName)
from cteForeignKeys
where referenced_object_id = OBJECT_ID(@TableName)

-- This can print only first 4000 chars. With many child tables the query may exceed this limit
print @SqlStatement

-- Use multiple print statements to dump parts of the query to Messages window. Delete the line breaks between sections to be able to execute the query
print SUBSTRING(@SqlStatement,     1,  4000)
print SUBSTRING(@SqlStatement,  4001,  8000)
print SUBSTRING(@SqlStatement,  8001, 12000)
print SUBSTRING(@SqlStatement, 12001, 16000)

-- Or execute it directly as dynamic SQL
-- exec sp_executesql @SqlStatement