Проверка операторов UPDATE и INSERT для всей таблицы - PullRequest
3 голосов
/ 18 июня 2009

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

Представьте себе следующую таблицу, описывающую патрули различных охранников (из предыдущего сценария сторожа)

PK  PatrolID Integer
FK  GuardID  Integer
    Starts   DateTime
    Ends     DateTime

Мы начнем с ограничения, указывающего, что время начала и окончания должно быть логическим:

Ends >= Starts

Однако я хочу добавить еще одно логическое ограничение: конкретный сторож (GuardID) не может находиться в двух местах одновременно, а это означает, что для любой записи период, указанный в Start / Ends, не должен перекрываться с периодом, определенным для любого другого патруль той же стражи.

Я могу придумать два способа попытаться приблизиться к этому:

Создать триггер INSTEAD OF INSERT. Этот триггер будет затем использовать курсоры для просмотра таблицы INSERTED, проверяя каждую запись. Если какая-либо запись конфликтует с существующей, возникает ошибка. У меня есть две проблемы с этим подходом: мне не нравится использовать курсоры в современной версии SQL Server, и я не уверен, как реализовать ту же логику для ОБНОВЛЕНИЙ. Также может быть сложность записей в INSERTED, конфликтующих друг с другом.

Второй, на первый взгляд, лучший подход заключается в создании CONSTRAINT, который вызывает пользовательскую функцию, передавая PatrolID, GuardID, Starts и Ends. Затем функция выполняет проверку запроса WHERE EXISTS для любых записей, которые перекрывают параметры GuardID / Starts / Ends, которые не являются исходной записью PatrolID. Однако я не уверен, какие потенциальные побочные эффекты может иметь этот подход.

Второй подход лучше? Кто-нибудь видит какие-либо подводные камни, например, при вставке / обновлении нескольких строк одновременно (здесь я обеспокоен тем, что строки в этой группе могут конфликтовать, то есть порядок, в который они «вставляются», имеет значение). Есть ли лучший способ сделать это (например, какой-нибудь причудливый трюк с INDEX?)

Ответы [ 4 ]

5 голосов
/ 18 июня 2009

Используйте триггер после, чтобы проверить, что ограничение перекрытия не было нарушено:

create trigger Patrol_NoOverlap_AIU on Patrol for insert, update as
    begin
    if exists (select *
        from inserted i
        inner join Patrol p
            on i.GuardId = p.GuardId
            and i.PatrolId <> p.PatrolId
        where (i.Starts between p.starts and p.Ends)
        or (i.Ends between p.Starts and p.Ends))

        rollback transaction
    end

ПРИМЕЧАНИЕ. Откат транзакции внутри триггера завершит пакет. В отличие от обычного нарушения правил, вы не сможете отследить ошибку.

Вы можете захотеть другое предложение where в зависимости от того, как вы определяете временной диапазон и перекрытие. Например, если вы хотите сказать, что Страж № 1 находится в точке Х с 6:00 до 7:00, то с 7:00 до 8:00 вышеуказанное не позволит. Вы хотели бы вместо:

create trigger Patrol_NoOverlap_AIU on Patrol for insert, update as
    begin
    if exists (select *
        from inserted i
        inner join Patrol p
            on i.GuardId = p.GuardId
            and i.PatrolId <> p.PatrolId
        where (p.Starts <= i.Starts and i.Starts < p.Ends)
        or (p.Starts <= i.Ends and i.Ends < p.Ends))

        rollback transaction
    end

Где начинается - время начала охраны, а Конец - бесконечно малый момент после окончания охраны.

3 голосов
/ 18 июня 2009

Самый простой способ - использовать хранимую процедуру для вставок. Хранимая процедура может выполнить вставку в одном выражении:

insert into YourTable
(GuardID, Starts, Ends)
select @GuardID, @Starts, @Ends
where not exists (
    select *
    from YourTable
    where GuardID = @GuardID
    and Starts <= @Ends
    and Ends >= @Start
)

if @@rowcount <> 1
    return -1 -- Failure

По моему опыту, триггеры и ограничения с UDF имеют тенденцию становиться очень сложными. У них есть побочные эффекты, которые могут потребовать много отладки, чтобы выяснить.

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

1 голос
/ 01 июля 2014
CREATE TRIGGER [dbo].[emaill] ON [dbo].[email]
FOR INSERT

AS

BEGIN


    declare @email CHAR(50);


    SELECT @email=i.email from inserted i;

    IF @email NOT LIKE '%_@%_.__%' 
    BEGIN
            print 'Triggered Fired';
            Print 'Invalid Emaill....';
            ROLLBACK TRANSACTION
    END 

END
0 голосов
/ 19 июня 2009
...