2015-01-16 69 views
1

我已經創建了一個觸發器,用於阻止表中已存在日期的插入記錄。假設容易觸發

CREATE TRIGGER [dbo].[SpecialOffers_Insert] 
ON [dbo].[SpecialOffers] 
FOR INSERT,UPDATE 
AS 
SET NOCOUNT ON 
IF EXISTS (SELECT * FROM inserted WHERE SPO_DateFrom IN (SELECT SPO_DateFrom FROM dbo.SpecialOffers)) 
BEGIN 
RAISERROR('Error. ', 16, 1) 
ROLLBACK TRAN 
SET NOCOUNT OFF 
RETURN 
END 
SET NOCOUNT OFF 

它被添加到一個表:

CREATE TABLE [dbo].[SpecialOffers](
[SPO_SpoId] [int] IDENTITY(1,1) NOT NULL, 
[SPO_DateFrom] [datetime] NOT NULL, 
[SPO_DateTo] [datetime] NOT NULL) 

表是空的,但試圖插入這樣的記錄時:

INSERT INTO dbo.SpecialOffers (SPO_DateFrom, SPO_DateTo) VALUES ('2015-01-15','2015-01-15') 

我從觸發錯誤。我應該如何修改觸發器來避免錯誤?

+0

?觸發器可以運行BEFORE插入(在記錄實際添加到表之前)或AFTER插入(當記錄已經添加到表並且由SELECT可見時)。 – Dmitry

+2

爲什麼不僅僅應用一個唯一的約束? –

回答

1

如果目標是阻止與日期已經在一個表中的現有插入的記錄,你並不需要一個觸發 - 剛剛創建的日期字段唯一約束:由於觸發器在運行

ALTER TABLE [dbo].[SpecialOffers] 
ADD CONSTRAINT SpecialOffersUQ UNIQUE (SPO_DateFrom) 
+0

與您的快速回答相比,實際目標是檢查SPO_DateFrom和SPO_DateTo之間的時間段,以便插入的時間段不會與存在的時間段重疊,因此必須處於觸發器中。任何想法如何處理觸發器? –

0

那燒吧,這INSERT後的SQL語句的事務上下文,有在表dbo.SpecialOffers一排你剛插入的SPO_DateFrom值和SELECT從表中一定會成功...

那裏因此,觸發器會假定已經有一個值 - 並且它會拋出錯誤(按照設計)。

可以觸發改寫爲不看新插入的行,但別的 - 但正如其他人所指出的,一個UNIQUE約束確實是更加簡單

+0

1。約束 - 它會幫助重疊的時期嗎? 2.觸發器排除新添加的記錄 - 是否有任何特殊的語法,或者我應該簡單地把NOT EXISTS(SELECT * FROM插入WHERE ...)? –

1

如果你想要一個觸發器,以防止重疊,你爲什麼不這樣說:

CREATE TABLE [dbo].[SpecialOffers](
    [SPO_SpoId] [int] IDENTITY(1,1) NOT NULL, 
    [SPO_DateFrom] [datetime] NOT NULL, 
    [SPO_DateTo] [datetime] NOT NULL, 
    constraint CK_SO_NoTimeTravel CHECK (SPO_DateFrom <= SPO_DateTo) 
) 
GO 
CREATE TRIGGER NoOverlaps 
on dbo.SpecialOffers 
after insert,update 
as 
    set nocount on 
    if exists (
     select * 
     from dbo.SpecialOffers so1 
       inner join 
      dbo.SpecialOffers so2 
       on 
        so1.SPO_DateFrom < so2.SPO_DateTo and 
        so2.SPO_DateFrom < so1.SPO_DateTo and 
        so1.SPO_SpoId != so2.SPO_SpoId 
       inner join 
      inserted i 
       on 
        so1.SPO_SpoId = i.SPO_SpoId 
     ) 
    begin 
     RAISERROR('No overlaps',16,1) 
     ROLLBACK 
    end 

例子:

--Works 
INSERT INTO SpecialOffers (SPO_DateFrom,SPO_DateTo) 
values ('20010101','20011231') 
GO 
--Fails (Trigger) 
INSERT INTO SpecialOffers (SPO_DateFrom,SPO_DateTo) 
values ('20010101','20011231') 
GO 
--Fails (Constraint) 
INSERT INTO SpecialOffers (SPO_DateFrom,SPO_DateTo) 
values ('20011231','20010101') 
GO 
--Fails (Trigger) 
INSERT INTO SpecialOffers (SPO_DateFrom,SPO_DateTo) 
values ('20020101','20021231'), 
     ('20020701','20030630') 

我也廣告檢查一個檢查約束,以便我不必處理觸發器中的無意義數據。

您可能需要更改掉一些< S的<=秒或反之亦然,這取決於你想用什麼定義的時間間隔(即是DateFromDateTo意思是包容獨家端點對於他們描述的間隔?)

+0

謝謝Damien。我會在一分鐘內測試。 –

+0

完美的作品。只有重疊條件需要一些修正。謝謝。 –

0

你應該檢查你發現的行是不是你剛纔插入的行。改變什麼RDBMS您正在使用線路

IF EXISTS (
     SELECT * FROM inserted 
     WHERE SPO_DateFrom IN (
      SELECT SPO_DateFrom 
      FROM dbo.SpecialOffers) 
    ) 

IF EXISTS (
     SELECT * FROM inserted a 
     WHERE SPO_DateFrom IN (
      SELECT SPO_DateFrom 
      FROM dbo.SpecialOffers b 
      WHERE a.SPO_SpoId <> b.SPO_SpoId) 
    )