如果不在sql server 2008之间插入数据?

时间:2014-11-06 14:30:10

标签: sql sql-server sql-server-2008 insert

如果我有这样的事件表:

    event_name     begin_date(pk) end_date(pk)
    ------------------------------------------
    holiday        2014-11-01     2014-11-05
    holiday        2014-11-10     2014-11-12
    big sale       2014-11-18     2014-11-25
    monthly sale   2014-11-28     2014-11-30

如果插入数据的begin_dateend_date处于任何事件期间,我如何阻止插入数据?

例:
不会插入此数据:

    holiday        2014-11-03     2014-11-08

将插入此数据:

    holiday        2014-11-06     2014-11-09

有人可以帮我解决这个问题吗?

3 个答案:

答案 0 :(得分:0)

最好的办法是在插入

之前避免使用触发器并检查是否存在
IF NOT EXISTS (SELECT TOP 1 1 FROM MyTable WHERE @InsertedEndDate > begin_date AND @InsertedBeginDate < end_date)
BEGIN
    --do actual insert/work
END

它是一个简单的检查,以找到第一个重叠。 Select TOP 1 1是一个避免实际获取数据的技巧,它会在匹配与您实际尝试保存的日期范围重叠的行时立即返回

答案 1 :(得分:0)

触发器应该是你的最后手段。如果您的应用程序使用存储过程,那么最好将验证放在那里。或者您可以使用check constraint。根据我对您的问题的理解,这是您需要使用的条件:

SELECT *
FROM Table
WHERE @begin_date BETWEEN begin_date AND end_date
OR @end_date BETWEEN begin_date AND end_date
OR @begin_date < begin_date AND @end_date > end_date

如果该查询返回任何行,则不应插入@begin_date@end_date值。

答案 2 :(得分:0)

我一直认为,如果某些东西可以在数据库中受到限制,那应该是。你永远不知道哪个开发人员会禁用触发器,或者绕过应用程序代码并直接运行插入,所以虽然触发器和业务逻辑很好,但它并不是万无一失的。

我要做的第一件事是将begin_date限制在end_date之前:

CREATE TABLE dbo.T
(
    ID INT IDENTITY(1, 1) NOT NULL,
    Event_name VARCHAR(50) NOT NULL,
    begin_date DATE NOT NULL,
    end_date DATE NOT NULL
);
ALTER TABLE dbo.T ADD CONSTRAINT CHK_T_ValidDates CHECK (Begin_date <= end_date);

然后(如果您还没有),您可以创建一个日历表(which are incredibly useful anyway):

CREATE TABLE dbo.Calendar 
(
    Date DATE NOT NULL
);
CREATE UNIQUE CLUSTERED INDEX UQ_Calendar_Date ON dbo.Calendar (Date);
GO
INSERT dbo.Calendar (Date)
SELECT  TOP (7305) DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, '20000101')
FROM    sys.all_objects a, sys.all_objects;
GO

最后,您可以创建一个索引视图,以确保表中没有重复的日期:

CREATE VIEW dbo.TCheck
WITH SCHEMABINDING
AS
    SELECT  c.Date
    FROM    dbo.T
            INNER JOIN dbo.Calendar AS c
                ON c.Date >= t.begin_date 
                AND c.Date <= t.end_date;
GO
CREATE UNIQUE CLUSTERED INDEX UQ_TCheck_ID ON dbo.TCheck (Date);

在我运行的测试中(与触发器相比),索引视图比触发器执行了大约50%,但都没有很好地执行。不幸的是,有时数据完整性会产生成本。