SQL Server: проверьте, существуют ли дочерние строки - PullRequest
0 голосов
/ 22 февраля 2011

Я работаю над веб-приложением, в котором много таблиц, но для иллюстрации моей проблемы достаточно двух:

  1. Пользователь
  2. Заказать

Допустим, у таблицы User есть первичный ключ "UserID", который является внешним ключом в таблице Order под названием "CreatedBy_UserID".

Прежде чем удалять пользователя, я хотел бы проверить, есть ли в таблице Order запись, созданная пользователем, который скоро будет удален.

Я знаю, что SqlException возникает, если я пытаюсь удалить пользователя, но допустим, что я хочу заранее проверить, что в таблице Order нет записей, созданных этим пользователем? Есть ли какой-нибудь код SQL, который я мог бы запустить, который проверит все внешние ключи таблицы, если на эту строку ссылаются?

Для меня это, как правило, полезный код, поскольку я мог бы вообще удалить опцию удаления, если можно обнаружить, что пользователь существует в этих других таблицах.

Мне не нужен простой запрос (SELECT COUNT(*) FROM Order WHERE CreatedBy_UserID == @userID), потому что он не будет работать, если я создам другой внешний ключ для таблицы Order. Вместо этого я хочу что-то, что будет проходить через все внешние ключи.

Можно ли это сделать?

Ответы [ 4 ]

1 голос
/ 22 февраля 2011

Ниже приведен код для 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)
0 голосов
/ 22 февраля 2011

Вы можете использовать транзакцию для проверки.Я знаю, что это похоже на каменный топор, но работает быстро и стабильно.

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;
}
0 голосов
/ 22 февраля 2011

Этот код даст вам список внешних ключей, которые определены для указанной таблицы:

выберите отличное имя из sys.objects, где object_id in (выберите constraint_object_id из sys.foreign_key_columns как fk
где fk.Parent_object_id = (выберите object_id из sys.tables, где name = 'tablename'))

0 голосов
/ 22 февраля 2011

Нет чистого способа перебора всех столбцов 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)
...

Вы не будете динамически перебирать каждое свойство некоторого пользовательского объекта и тестировать каждый из них в целом?У вас будет код для каждого свойства

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...