SQL Server:ROLLBACK TRANSACTION请求没有相应的BEGIN TRANSACTION

时间:2018-05-10 17:00:20

标签: sql-server tsql triggers database-cursor

我有一个可以工作的触发器(它必须触发)但我仍然会收到错误。 我理解错误但我不知道如何解决它。

我尝试将一些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

修改

好的,所以我在没有光标的情况下尝试了你的答案(我明白我的方式显然不是最好的!)但是现在它没有用。

我的目标:我有一个DB来预订航班。在这个数据库中,我有一张桌子&#34; Tranche&#34;谁包含一些日期和一些价格(取决于航班时间)。

我需要预防和避免生日的任何重叠,例如:

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

因此,当我尝试插入17y-63y时,我的触发器必须触发:xx€(因为我已经为这些年龄段定价)。

对不起,如果我的英语不是很完美btw!

这是我的桌子&#34; Tranche&#34;:

https://i.stack.imgur.com/KuQH8.png

TRA_Vol_ID是另一个表的外键&#34; Vol&#34;谁包含航班

这是我的代码:

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 个答案:

答案 0 :(得分:2)

我真的不知道OP的目标是什么。但是,我想发布一个小例子如何进行数据集方法,以及如何一次性检查所有行。

目前,如果用户插入1行,OP的触发器将仅“工作”。更多,事情不会正常工作。然后我们也遇到CURSOR的问题。我注意到游标的声明根本没有引用inserted,所以我实际上并不知道它们的目标是什么。看起来更像OP在发生INSERT时审计表中已有的数据,而不是正在插入的数据。这看起来很奇怪。

无论如何,这不是OP的解决方案,但是,我没有足够的空间来评论所有这些。也许它会把OP推向正确的方向。

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问题;问题不在于CURSORROLLBACK,此触发器的问题更为根本。我建议修改你的问题并实际解释你想要用Trigger做什么的目标。为您的表CREATE提供DDL,为任何样本数据提供INSERT语句。您可能还想提供一些INSERT语句,这些语句会对您的触发器产生不同的结果(确保包含一次插入多行的那些语句)。

我意识到这是更多的评论,然而,再一次,我没有足够的空间评论我写这一切。 :)