如果任何行引用要通过FK删除的行,则无法删除行。
在执行DELETE语句之前,是否可以知道是否有任何行引用了要删除的行?
答案 0 :(得分:20)
此脚本将显示所有包含引用您要删除的行的行的表:
declare @RowId int = 1
declare @TableName sysname = 'ParentTable'
declare @Command varchar(max)
select @Command = isnull(@Command + ' union all ', '') + 'select ''' + object_name(parent_object_id) +
''' where exists(select * from ' + object_name(parent_object_id) + ' where ' + col.name+ ' = ' + cast(@RowId as varchar) + ')'
from sys.foreign_key_columns fkc
join sys.columns col on
fkc.parent_object_id = col.object_id and fkc.parent_column_id = col.column_id
where object_name(referenced_object_id) = @TableName
execute (@Command)
假设外键不是复合的。
答案 1 :(得分:3)
选项1(检测):
您执行Select Statement
以确定是否有任何记录引用了要删除的记录 - 如果您希望,则,手动删除那些引用它的记录。这也可以使用触发器完成,虽然我建议不要使用触发器,因为它们往往会让人(和你自己)感到惊讶。
选项2(自动化):
您可以查看Cascading Deletes,如果配置正确,将导致所有引用要删除的记录的记录也被删除。
何时使用级联删除(由Joel Coehoorn撰写的文字转述)
以下是关于stackoverflow的Cascading Deletes的精彩讨论。
答案 2 :(得分:0)
没有人提到它,但只是为了记录我使用了很多程序
sp_helpconstraint 'dbo.mytable'
为了找到与dbo.mytable相关的所有约束,以及哪些表引用dbo.mytable。 我发现它非常有用和方便。
答案 3 :(得分:0)
我改进了Alex Aza的解决方案。
我使用softdelete,所以必须添加一个列"删除"在条件"其中" 。 而且我在TSQL中创建了一个函数,它在表中表示NHibernate中继承的对象时发现,而PK是来自父表的FK。
如下:
declare @RowId int = 4
declare @TableName sysname = 'TABLE'
declare @Command varchar(max)
select @Command = isnull(@Command + ' union all ', '') + 'select ''' + object_name(parent_object_id) +
''' where exists(select * from ' + object_name(parent_object_id) +
CASE
WHEN EXISTS(select object_name(object_id) from sys.columns col where name = 'deleted' and object_id = parent_object_id)
THEN ' where ' + col.name+ ' = ' + cast(@RowId as varchar) +' and deleted = 0 '
when dbo.ParentIdFromTable(object_name(parent_object_id)) <> ''
then ' inner join ' + dbo.ParentIdFromTable(object_name(parent_object_id)) + ' on id = ' + dbo.PrimaryKey(object_name(parent_object_id))
+' where ' + col.name+ ' = ' + cast(@RowId as varchar) +' and deleted = 0 '
else
' where ' + col.name+ ' = ' + cast(@RowId as varchar)
END
+ ')'
from sys.foreign_key_columns fkc
join sys.columns col on
fkc.parent_object_id = col.object_id and fkc.parent_column_id = col.column_id
where object_name(referenced_object_id) = @TableName
PRINT @Command
execute (@Command)
Depedencies职能:
CREATE FUNCTION dbo.ParentIdFromTable(@Table varchar(255))
RETURNS varchar(255)
AS
BEGIN
declare @tableParent varchar(255) = ''
if exists(select pk.TABLE_NAME, pk.COLUMN_NAME, col.name, object_name(referenced_object_id) Referenced, object_name(parent_object_id) as Parent
from sys.columns col
inner join sys.foreign_key_columns fkc on
fkc.parent_object_id = col.object_id and fkc.parent_column_id = col.column_id
inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE pk on
pk.TABLE_NAME = object_name(object_id) and pk.COLUMN_NAME = col.name
WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1
AND table_name = @table)
begin
while exists(select *
from sys.columns col
inner join sys.foreign_key_columns fkc on
fkc.parent_object_id = col.object_id and fkc.parent_column_id = col.column_id
inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE pk on
pk.TABLE_NAME = object_name(object_id) and pk.COLUMN_NAME = col.name
WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1 AND table_name = @table)
begin
-- Descobrir o parent, column
select @tableParent = object_name(referenced_object_id)
from sys.columns col
inner join sys.foreign_key_columns fkc on
fkc.parent_object_id = col.object_id and fkc.parent_column_id = col.column_id
inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE pk on
pk.TABLE_NAME = object_name(object_id) and pk.COLUMN_NAME = col.name
WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1
AND table_name = @table
--print @tableParent
set @table = @tableParent
end
end
return @tableParent;
END;
GO
CREATE FUNCTION dbo.PrimaryKey(@Table varchar(255))
RETURNS varchar(255)
AS
BEGIN
declare @columnName varchar(255) = ''
-- Descobrir o parent, column
select @columnName = COLUMN_NAME
from INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1
AND table_name = @Table
return @columnName
end;