如果SQL Server触发器中的语句不起作用

时间:2018-03-10 12:21:28

标签: sql-server tsql triggers

我创建了这个表:

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id =OBJECT_ID(N'[dbo].[czlonkowie_jednostek]') AND type IN (N'U'))
BEGIN
    CREATE TABLE [dbo].[czlonkowie_jednostek]
    (
            [id_czlonkostwa] [int] IDENTITY(1,1) NOT NULL,
            [id_uzytkownika] [int] NOT NULL,
            [id_jednostki] [int] NOT NULL,
            [data_od_przynaleznosci] [date],
            [data_do_przynaleznosci] [date]
    ) ON [PRIMARY]
END

其中id_uzytkownika和id_jednostki是外键。

还有一个触发器负责检查新插入的id_uzytkownika是否与此id_uzytkownika的早期记录的时间不一致:

IF EXISTS (SELECT name FROM sys.triggers 
           WHERE Name = 'PilnujCzlonkowJednostki')
    DROP TRIGGER PilnujCzlonkowJednostki
GO

CREATE TRIGGER PilnujCzlonkowJednostki 
ON [dbo].[czlonkowie_jednostek]
FOR INSERT
AS
DECLARE @wstawiany_poczatek date
DECLARE @wstawiany_koniec date
DECLARE @wstawiany_czlonek int
DECLARE @ile int

-- czy tylko 1 czlonkostwo
SELECT @ile = COUNT(*) FROM inserted

IF @ile > 1
BEGIN
    raiserror ('wstawienie wiecej niz jednego czlonka jednoczesnie zabronione - anulowano!',16,1)
    rollback
    return
END

SELECT 
    @wstawiany_czlonek = id_uzytkownika,
    @wstawiany_poczatek = data_od_przynaleznosci,
    @wstawiany_koniec = data_do_przynaleznosci  
FROM 
    inserted

--przeglad istniejacych wpisow
DECLARE @czlonek_baza int
DECLARE @poczatek_baza date
DECLARE @koniec_baza date

DECLARE kursor CURSOR FOR
    SELECT id_uzytkownika, data_od_przynaleznosci,data_do_przynaleznosci
    FROM czlonkowie_jednostek

OPEN kursor

FETCH NEXT FROM kursor
INTO @czlonek_baza, @poczatek_baza, @koniec_baza;

WHILE @@FETCH_STATUS = 0
BEGIN
    IF ((@wstawiany_czlonek = @czlonek_baza AND (@wstawiany_poczatek between @poczatek_baza and @koniec_baza))
    OR
    (@wstawiany_czlonek = @czlonek_baza AND (@wstawiany_koniec between @poczatek_baza and @koniec_baza))
    OR
    (@wstawiany_czlonek = @czlonek_baza AND (@wstawiany_poczatek <= @poczatek_baza and @wstawiany_koniec >= @koniec_baza)))
    BEGIN
    raiserror('Wstawiany czlonek jest czlonkiem innej jednostki w tym samym czasie!',16,1)
    rollback
    CLOSE kursor
    DEALLOCATE kursor
    return
    END

    FETCH NEXT FROM kursor
    INTO @czlonek_baza, @poczatek_baza, @koniec_baza;
END

CLOSE kursor
DEALLOCATE kursor
GO

在执行触发器脚本期间,一切看起来都很好不幸的是,当我试图将记录记录到TABLE [dbo]。[czlonkowie_jednostek]时,尽管表格为空,但触发器似乎执行IF语句。

我想插入的代码:

INSERT INTO [dbo].[czlonkowie_jednostek] ([id_uzytkownika],[id_jednostki],[data_od_przynaleznosci],[data_do_przynaleznosci])
VALUES(13,2,'1997-09-01','2000-08-31')

我收到服务器的响应:

  

Msg 50000,Level 16,State 1,Procedure PilnujCzlonkowJednostki,Line 257   Wstawiany czlonek jest czlonkiem innej jednostki w tym samym czasie!   消息3609,级别16,状态1,行213   交易在触发器中结束。批次已中止。

你能看到我错过了什么吗?

1 个答案:

答案 0 :(得分:0)

执行插入后触发器会触发,因此当您循环遍历dbo.czlonkowie_jednostek记录时,您尝试插入的行也会被处理。 所以我会选择这样的东西(删除CURSOR):

ALTER TRIGGER PilnujCzlonkowJednostki 
ON [dbo].[czlonkowie_jednostek]
FOR INSERT
AS
BEGIN
    DECLARE @inserted_id_czlonkostwa INT
    SELECT @inserted_id_czlonkostwa = IDENT_CURRENT('dbo.czlonkowie_jednostek')

    DECLARE @wstawiany_poczatek date
    DECLARE @wstawiany_koniec date
    DECLARE @wstawiany_czlonek int
    DECLARE @ile INT

    -- czy tylko 1 czlonkostwo
    SELECT @ile = COUNT(*) FROM inserted

    IF @ile > 1
    BEGIN
        raiserror ('wstawienie wiecej niz jednego czlonka jednoczesnie zabronione - anulowano!',16,1)
        rollback
        return
    END

    SELECT 
        @wstawiany_czlonek = id_uzytkownika,
        @wstawiany_poczatek = data_od_przynaleznosci,
        @wstawiany_koniec = data_do_przynaleznosci  
    FROM 
        INSERTED

    PRINT @inserted_id_czlonkostwa

    IF EXISTS(SELECT *
        FROM czlonkowie_jednostek cj
        WHERE ((@wstawiany_czlonek = cj.id_uzytkownika AND (@wstawiany_poczatek between cj.data_od_przynaleznosci and cj.data_do_przynaleznosci))
            OR
            (@wstawiany_czlonek = cj.id_uzytkownika AND (@wstawiany_koniec between cj.data_od_przynaleznosci and cj.data_do_przynaleznosci))
            OR
            (@wstawiany_czlonek = cj.id_uzytkownika AND (@wstawiany_poczatek <= cj.data_od_przynaleznosci and @wstawiany_koniec >= cj.data_do_przynaleznosci))
            )
            AND cj.id_czlonkostwa <> @inserted_id_czlonkostwa
        )
    BEGIN
        raiserror('Wstawiany czlonek jest czlonkiem innej jednostki w tym samym czasie!',16,1)
        rollback
        return
    END
END
GO