如果外键表中不存在数据,我想从主键表中删除数据。几乎有25个子表。
答案 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