SQL Server: у запроса ROLLBACK TRANSACTION нет соответствующей BEGIN TRANSACTION

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

Я пытался установить НЕКОТОРЫЕ СДЕЛКИ со всем кодом, который идет с ним, но я думаю, что моя грамматика неверна, потому что у меня всегда тайм-аут!

Итак, мой вопрос, где именно я должен поставить свой BEGIN TRANSACTION заявления в моем коде?

Кроме того, мне нужно 3 BEGIN TRANSACTION заявления, так как у меня есть 3 ROLLBACK?

Заранее спасибо!

Мой код:

ALTER TRIGGER [dbo].[Tr_CheckOverlap]
ON [dbo].[Tranche]
FOR INSERT
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @IdVol INT, @IdTranche INT, 
            @AgeMinInserted DATE, @AgeMaxInserted DATE

    SELECT @AgeMinInserted = t.TRA_Age_Min 
    FROM Tranche t
    JOIN inserted AS i ON t.TRA_Id = i.TRA_Id

    SELECT @AgeMaxInserted = t.TRA_Age_Max 
    FROM Tranche t
    JOIN inserted AS i ON t.TRA_Id = i.TRA_Id

    DECLARE CR_TrancheVol CURSOR FOR 
        SELECT t.TRA_Vol_Id,t.TRA_Id
        FROM Tranche t
        JOIN inserted AS i ON t.TRA_Vol_Id = i.TRA_Vol_Id;

    OPEN CR_TrancheVol

    FETCH CR_TrancheVol INTO @IdVol, @IdTranche

    WHILE( @@FETCH_STATUS = 0)
    BEGIN
        DECLARE @AgeMin DATE, @AgeMax DATE

        SELECT @AgeMin = t.TRA_Age_Min 
        FROM Tranche t
        WHERE t.TRA_Id = @IdTranche

        SELECT @AgeMax = t.TRA_Age_Max 
        FROM Tranche t
        WHERE t.TRA_Id = @IdTranche

        IF @AgeMinInserted > @AgeMin AND @AgeMinInserted < @AgeMax
        BEGIN
            PRINT 'Trans1'
            RAISERROR('Overlap: Date de naissance minimum déjà couverte', 1, 420)
            ROLLBACK TRANSACTION
        END

        IF @AgeMaxInserted > @AgeMin AND @AgeMaxInserted < @AgeMax
        BEGIN
            PRINT 'Trans2'
            RAISERROR('Overlap: Date de naissance maximum déjà couverte', 1, 421)
            ROLLBACK TRANSACTION
        END

        IF @AgeMinInserted < @AgeMin AND @AgeMaxInserted > @AgeMax
        BEGIN
            PRINT 'Trans3'
            RAISERROR('Overlap: Tranche déjà couverte complètement', 1, 422)
            ROLLBACK TRANSACTION
        END

        FETCH CR_TrancheVol INTO @IdVol, @IdTranche
    END

    CLOSE CR_TrancheVol
    DEALLOCATE CR_TrancheVol
END

РЕДАКТИРОВАТЬ:

Итак, я попробовал ваш ответ без курсора (я понимаю, что мой путь был явно не лучшим!), Но пока он не работает.

Моя цель: у меня есть БД, чтобы забронировать рейс. В этой базе данных у меня есть таблица "Транш", в которой указаны некоторые даты и цены (в зависимости от времени полета).

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

1y-17y: 80€
18y-64y: 120€

Так что мой триггер должен срабатывать, когда я пытаюсь вставить 17y-63y: xx € (потому что у меня уже есть цена для этих возрастов).

Извините, если мой английский не идеален, кстати!

Вот мой стол "Транш":

TRA_Vol_ID - это внешний ключ другой таблицы "Vol", которая содержит рейсы

Вот код, который у меня есть:

ALTER TRIGGER [dbo].[Tr_CheckOverlap]
ON [dbo].[Tranche]
FOR INSERT
AS
BEGIN
    /*
    Some SQL goes here to get the value of Minimum age.
    I assuming that it doesn't vary by entry, however,
    I don't really have enough information to go on to tell
    */
    SET NOCOUNT ON;

    DECLARE @MinAge DATE, @MaxAge DATE

    SELECT @MinAge = t.TRA_Age_Min 
    FROM Tranche t
    JOIN Vol AS v ON v.VOL_Id = t.TRA_Vol_Id
    JOIN inserted AS i ON t.TRA_Id = i.TRA_Id
    WHERE t.TRA_Id = i.TRA_Id

    SELECT @MaxAge = t.TRA_Age_Max
    FROM Tranche t
    JOIN inserted AS i ON t.TRA_Id = i.TRA_Id
    JOIN Vol AS v ON v.VOL_Id = t.TRA_Vol_Id
    WHERE t.TRA_Id = i.TRA_Id

    IF (SELECT COUNT(CASE WHEN i.TRA_Age_Min > @MinAge AND i.TRA_Age_Min < @MaxAge  THEN 1 END) FROM inserted i) > 0 
    BEGIN
        RAISERROR('Overlap: Birthday min reached',1,430);
        ROLLBACK
    END
    ELSE IF (SELECT COUNT(CASE WHEN i.TRA_Age_Max > @MinAge AND i.TRA_Age_Max < @MaxAge  THEN 1 END) FROM inserted i) > 0 
    BEGIN
        RAISERROR('Overlap: Birthday max reached',1,430);
        ROLLBACK
    END
END

1 ответ

Я действительно не знаю, каковы цели ОП здесь. Тем не менее, я хотел опубликовать небольшой пример, как сделать подход к набору данных и как проверить все строки за один раз.

В настоящий момент триггер, который имеет OP, будет "работать" только в том случае, если пользователь вставляет 1 строку. Больше, и вещи не будут работать должным образом. Тогда у нас также есть проблема CURSOR, Я отмечаю, что объявление курсоров не ссылается inserted вообще, так что я на самом деле не знаю, каковы их цели. Похоже, что ОП проверяет данные, уже находящиеся в таблице, когда INSERT происходит, а не данные, которые вставляются. Это кажется очень странным.

Во всяком случае, это не решение для ОП, однако, мне не хватает места в комментарии, чтобы поместить все это. Может быть, это подтолкнет ОП в правильном направлении.

ALTER TRIGGER [dbo].[Tr_CheckOverlap]
ON [dbo].[Tranche]
FOR INSERT
AS
BEGIN

    /*
    Some SQL goes here to get the value of Minimum age.
    I assuming that it doesn't vary by entry, however,
    I don't really have enough information to go on to tell
    */

    IF (SELECT COUNT(CASE WHEN i.Age < @MinAge THEN 1 END) FROM inserted i) > 0 BEGIN
        RAISERROR('Age too low',1,430);
        ROLLBACK
    END
    ELSE
    IF (SELECT COUNT(CASE WHEN i.Age > @MaxAge THEN 1 END) FROM inserted i) > 0 BEGIN
        RAISERROR('Age too high',1,430);
        ROLLBACK
    END


END

Вопрос под рукой, кажется, очень много xy вопрос; проблема не в CURSOR или ROLLBACKпроблемы с этим триггером гораздо более фундаментальные. Я бы предложил пересмотреть ваш вопрос и на самом деле объяснить вашу цель того, что вы хотите сделать со своим триггером. Предоставить DDL для CREATE ваш стол и INSERT заявления для любых образцов данных. Вы можете также предоставить некоторые INSERT операторы, которые будут иметь разные результаты для вашего триггера (не забудьте включить те, которые имеют более одной строки для вставки за один раз).

Я понимаю, что это больше комментирует, однако, опять же, мне явно не хватает места, чтобы написать все это.:)

Другие вопросы по тегам