16

如果任何行通过 FK 引用要删除的行,则无法删除该行。

是否有可能在执行 DELETE 语句之前知道是否有任何行正在引用要删除的行?

4

4 回答 4

24

此脚本将显示所有包含引用您尝试删除的行的行的表:

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)

假设外键不是复合的。

于 2011-06-10T05:19:35.300 回答
3

选项 1(检测)

您执行 aSelect Statement以确定是否有任何记录正在引用要删除的记录 -如果您愿意,可以手动删除那些引用它的记录。这也可以使用触发器来完成,尽管我建议不要使用触发器,因为它们往往会让人们(和你自己)在路上感到惊讶。

选项 2(自动化)

您可以查看级联删除,如果配置正确,将导致引用要删除的记录的所有记录也被删除。

何时使用级联删除(由Joel Coehoorn撰写的文字解释)

  • 当关系的语义可能涉及“是”描述时,级联删除可能有意义。示例:网络订单、网络订单行项目
  • 如果您要保留历史记录或使用仅设置已删除位列的软删除,则不应使用级联删除
  • 如果您错误地设置了外键,级联可能会给您带来麻烦。
  • 在完全理解之前使用级联是不明智的。但是,它是一个有用的功能,因此值得花时间去理解。

这是关于 stackoverflow上级联删除的精彩讨论。

于 2011-06-10T04:28:14.827 回答
0

没有人提到它,但只是为了记录,我使用了很多程序

sp_helpconstraint 'dbo.mytable'

为了找到所有与 dbo.mytable 相关的约束,以及哪些表引用了 dbo.mytable。我觉得它非常有用和方便。

于 2014-04-30T09:35:36.933 回答
0

我改进了 Alex Aza 的解决方案。

我使用softdelete,所以有必要在条件“where”中添加一列“delete”。我在 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)

依赖函数:

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;
于 2014-07-04T17:34:59.210 回答