SQL Server:检查子行是否存在

时间:2011-02-22 11:20:58

标签: c# sql sql-server foreign-keys

我正在开发一个Web应用程序,其中有很多表,但有两个表足以说明我的问题:

  1. 用户
  2. 顺序
  3. 我们假设User表有一个主键“UserID”,它是Order表中名为“CreatedBy_UserID”的外键。

    在删除用户之前,我想检查一下Order表是否有即将被删除的用户创建的记录。

    我知道如果我尝试删除用户会发生SqlException,但是让我们说我想事先检查Order表是否没有该用户创建的任何记录?是否有任何我可以运行的SQL代码,如果正在引用该行,它将检查表的所有外键?

    这对我来说通常是有用的代码,因为如果可以检测到用户存在于这些其他表中,我可以完全删除删除选项。

    我不想要一个简单的查询(SELECT COUNT(*) FROM Order WHERE CreatedBy_UserID == @userID),因为如果我为Order表创建另一个外键,这将不起作用。相反,我想要一些能够遍历所有外键的东西。

    可以这样做吗?

4 个答案:

答案 0 :(得分:1)

下面是我过去用来执行此任务的sp的代码(请原谅缩进):

create proc dbo.usp_ForeignKeyCheck(
@tableName varchar(100),
@columnName varchar(100),
@idValue int
) as begin


set nocount on

declare fksCursor cursor fast_forward for
select tc.table_name, ccu.column_name
from 
    information_schema.table_constraints tc join
    information_schema.constraint_column_usage ccu on tc.constraint_name = ccu.constraint_name join
    information_schema.referential_constraints rc on tc.constraint_name = rc.constraint_name join
    information_schema.table_constraints tc2 on rc.unique_constraint_name = tc2.constraint_name join
    information_schema.constraint_column_usage ccu2 on tc2.constraint_name = ccu2.constraint_name 
where tc.constraint_type = 'Foreign Key' and tc2.table_name = @tableName and ccu2.column_name = @columnName
order by tc.table_name

declare 
    @fkTableName varchar(100),
    @fkColumnName varchar(100),
    @fkFound bit,
    @params nvarchar(100),
    @sql nvarchar(500)

open fksCursor

fetch next from fksCursor
into @fkTableName, @fkColumnName

set @fkFound = 0
set @params=N'@fkFound bit output'

while @@fetch_status = 0 and coalesce(@fkFound,0) <> 1 begin

    select @sql = 'set @fkFound = (select top 1 1 from [' + @fkTableName + '] where [' + @fkColumnName + '] = ' + cast(@idValue as varchar(10)) + ')'
    print @sql
    exec sp_executesql @sql,@params,@fkFound output

    fetch next from fksCursor
    into @fkTableName, @fkColumnName

end

close fksCursor
deallocate fksCursor

select coalesce(@fkFound,0)

return 0
    end

如果某行有任何外键引用,则会选择值1。

您需要的电话是:

exec usp_ForeignKeyCheck('User','UserID',23)

答案 1 :(得分:0)

没有干净的方法来遍历存在多个FK列的所有FK列。您必须构建一些动态SQL来查询系统表并依次测试每个表。

就个人而言,我不会这样做。我知道我有什么FK:我会轮流测试每个

...
IF EXISTS (SELECT * FROM Order WHERE CreatedBy_UserID == @userID)
    RAISERROR ('User created Orders ', 16, 1)
IF EXISTS (SELECT * FROM Order WHERE PackedBy_UserID == @userID)
    RAISERROR ('User packed Orders', 16, 1)
...

你不会动态迭代某个用户对象的每个属性,并且通常会测试每个属性吗?你有每个属性的代码

答案 2 :(得分:0)

此代码将为您提供为特定表定义的外键列表:

从sys.objects中选择不同的名称 其中object_id in(从sys.foreign_key_columns中选择constraint_object_id为fk
其中fk.Parent_object_id =(从sys.tables中选择object_id 其中name ='tablename'))

答案 3 :(得分:0)

您可以使用交易进行检查。 我知道它看起来像石斧,但它工作快速而稳定。

private bool TestUser(string connectionString, int userID)
{
    var result = true;

    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();

        var command = connection.CreateCommand();
        var transaction = connection.BeginTransaction();

        command.Connection = connection;
        command.Transaction = transaction;

        try
        {
            command.CommandText = "DELETE User WHERE UserID = " + userID.ToString();
            command.ExecuteNonQuery();
            transaction.Rollback();
        }
        catch
        {
            result = false;
        }
    }

    return result;
}