2015-01-16 2 views
1

나는 테이블에 이미있는 날짜로 삽입 된 레코드를 차단하는 트리거를 만들었습니다.쉽게 방아쇠

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

테이블이 비어 있지만, 이러한 기록을 삽입하려고 할 때 :

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 

는 테이블에 추가

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

을 나는 트리거에서 오류가 발생했습니다. 오류가 발생하지 않도록 트리거를 어떻게 수정해야합니까?

+0

에 라인

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

변경? 트리거는 삽입하기 전에 (레코드가 테이블에 실제로 추가되기 전) 또는 삽입 후 (레코드가 이미 테이블에 추가되고 SELECT에 의해 사용자에게 표시되는 경우) 실행할 수 있습니다. – Dmitry

+2

왜 고유 제한을 적용하지 않는 것이 좋을까요? –

답변

1

목표는 날짜가 이미 테이블에 기존에 삽입 된 레코드를 차단하는 경우에는 트리거가 필요하지 않습니다 - 단지 날짜 필드에 고유 제한 조건 작성 : 트리거에서 실행되므로

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

빠른 답변을 드릴까요?하지만 실제 목표는 SPO_DateFrom과 SPO_DateTo 사이의 마침표를 확인하여 삽입 된 마침표가 기존 마침표와 겹치지 않도록 트리거에 있어야합니다. 방아쇠를 어떻게 해야할지 아는 어떤 생각? –

0

을 이 INSERT 후, 그것을 발사 SQL 문의 트랜잭션 (transaction) 문맥이있다 는 ... 방금 삽입 한 SPO_DateFrom 가치와 성공 테이블에서 SELECT와 테이블 dbo.SpecialOffers의 행 될 것

그곳에 앞에서 트리거는 이미 값이 있다고 가정하고 오류 (설계된대로)를 발생시킵니다.

당신은 새로 삽입 된 행 보지에 트리거를 다시 작성할 수 있지만, 아무것도 다른 -하지만 다른 사람들이 지적 등의 UNIQUE 제약 조건이 훨씬 더 간단하게

+0

1.제약 조건 - 기간이 겹치는 데 도움이됩니까? 2. 새로 추가 된 레코드를 제외하는 트리거 - 거기에 특별한 구문이 있습니까? 아니면 단순히 존재하지 않게해야합니까? (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 또는 그 반대를 위해 스왑에게 <의 일부를 변경해야 할 수도 있습니다 (예입니다 DateFrom포함 또는 독점 엔드 포인트로 의미 DateTo 그들은 설명하는 간격 동안?)

+0

감사합니다. Damien. 나는 그것을 잠시 후에 시험 할 것이다. –

+0

완벽하게 작동합니다. 기간이 겹치는 기간 만 수정해야했습니다. 고맙습니다. –

0

발견 한 행이 방금 삽입 한 행이 아닌지 확인해야합니다. 사용하는 RDBMS 무엇

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