我已经创建了一个触发器,用于阻止插入的记录,并在表格中存在日期。
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 :(得分:1)
如果目标是阻止表中已存在日期的插入记录,则不需要触发器 - 只需在日期字段上创建唯一约束:
ALTER TABLE [dbo].[SpecialOffers]
ADD CONSTRAINT SpecialOffersUQ UNIQUE (SPO_DateFrom)
答案 1 :(得分: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')
我还添加了一个检查约束,以便我不必处理触发器中的无意义数据。
您可能必须更改<
的某些<=
的交换,反之亦然,具体取决于您要使用的时间间隔的定义(即DateFrom
和{ {1}}意味着包含或独占端点,用于他们描述的时间间隔?)
答案 2 :(得分:0)
由于触发器在触发它的SQL语句的事务上下文中运行,因此在INSERT
之后,将表dbo.SpecialOffers
中的一行{您刚刚插入的{1}}值,表中的SPO_DateFrom
将成功...
因此,触发器将假定已存在一个值 - 并且它会抛出错误(按设计)。
你可以重写触发器以不查看新插入的行,但是其他任何东西 - 但正如其他人所指出的那样,SELECT
约束更简单地执行
答案 3 :(得分:0)
您应该检查您找到的行是否实际上不是您刚刚插入的行。改变行
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)
)