Sql server 日期范围重叠检查约束

Sql server 日期范围重叠检查约束,sql-server,database,sql-server-2005,database-design,check-constraints,Sql Server,Database,Sql Server 2005,Database Design,Check Constraints,我在SQLServer2005中有一个简单的表,有3列:DateStart、DateEnd和Value。我试图设置一个表检查约束,以避免插入重叠的记录。例如,如果在这样的表中有一个日期开始=2012-01-01 1月1日和日期结束2012-01-15 1月15日的记录,则检查约束必须避免插入日期开始=2012-01-10不关心日期结束的记录、日期结束=2012-01-10不关心日期开始的记录或日期开始2011-12-10和日期结束2012-02-01的记录 我以以下方式定义了UDF: CREAT

我在SQLServer2005中有一个简单的表,有3列:DateStart、DateEnd和Value。我试图设置一个表检查约束,以避免插入重叠的记录。例如,如果在这样的表中有一个日期开始=2012-01-01 1月1日和日期结束2012-01-15 1月15日的记录,则检查约束必须避免插入日期开始=2012-01-10不关心日期结束的记录、日期结束=2012-01-10不关心日期开始的记录或日期开始2011-12-10和日期结束2012-02-01的记录

我以以下方式定义了UDF:

CREATE FUNCTION [dbo].[ufn_checkOverlappingDateRange]
(
    @DateStart AS DATETIME
    ,@DateEnd AS DATETIME
)
RETURNS BIT 
AS
BEGIN
  DECLARE @retval BIT
  /* date range at least one day */
  IF (DATEDIFF(day,@DateStart,@DateEnd) < 1)
    BEGIN
      SET @retval=0
    END
  ELSE
    BEGIN
      IF EXISTS
        (
          SELECT
              *
            FROM [dbo].[myTable]
            WHERE
            ((DateStart <= @DateStart) AND (DateEnd > @DateStart))
            OR
            ((@DateStart <= DateStart) AND (@DateEnd > DateStart))
        )
        BEGIN
          SET @retval=0
        END
    ELSE
      BEGIN
            SET @retval=1
          END
        END
  RETURN @retval
END
然后我想检查可能是这样的:

ALTER TABLE [dbo].[myTable]  WITH CHECK ADD  CONSTRAINT [CK_OverlappingDateRange] CHECK  ([dbo].[ufn_checkOverlappingDateRange]([DateStart],[DateEnd])<>(0))
但即使使用[myTable]empty EXISTS,当我插入第一条记录时,运算符也会返回true。我在哪里?可以这样设置约束吗


BTW,我认为DATESART包含在范围内,DateEnd从范围中排除。

< P>在插入行之后执行检查,因此范围与自身重叠。

您需要修改您的WHERE以包含如下内容:@MyTableId MyTableId

顺便说一句,你的WHERE表达式可以简化

如果出现以下情况,则范围不重叠:

一个范围的结束在另一个范围的开始之前 或者一个范围的开始在另一个范围的结束之后。 可以用SQL编写,如:

WHERE @DateEnd < DateStart OR DateEnd < @DateStart
因此,您的最终目标应该是:

WHERE
    @MyTableId <> MyTableId
    AND @DateEnd >= DateStart
    AND DateEnd >= @DateStart

注意:要允许范围接触,请在最终表达式中使用。

我只想在DateEnd为null的情况下添加答案,因为我目前有这样的情况

当您保存打孔日志且用户仍在登录时,可能会发生这种情况

WHERE
    @MyTableId <> MyTableId
    AND @DateEnd >= DateStart
    AND DateEnd >= @DateStart
    OR @DateEnd >= DateStart
    AND DateEnd is null
    OR @DateStart >= DateStart
    AND DateEnd is null

我不知道这个查询在性能方面有多好,我肯定有办法对其进行优化。

考虑只对同一id(不是键而是其他列的值)避免间隔重叠,我的意思是,不是避免表级重叠,而是只对属于同一id的某些项。。有可能吗?但在使用读提交快照隔离时,这种方法不一致?由于每个事务在事务开始时都有自己的快照,这可能导致两个事务都看到它们以有效状态结束,即事务B不会看到事务a已经添加了一行,这将导致overlap@neo112对非快照隔离也存在竞争条件。这可以通过锁定具有明显可伸缩性后果的整个表来解决,或者非常小心地锁定单个行,而不是原始表中的行,而是预定义日期范围的特殊表中的行。谢谢你指出这个问题-我可能应该在我的回答中提到这些复杂的问题…@LeonardoLopez就我所知,这不是一个记录在案的行为,所以你不应该在可能的情况下依赖它,当然-最好是写检查,不知道它们是在什么时候被实际评估的。话虽如此,这似乎是SQL Server中长期存在的行为,您可以在执行计划中直接看到:资产节点将始终位于诸如聚集索引插入或聚集索引更新之类的节点之上,这意味着它将在以后执行。@LeonardoLopez您也可以从调试器中看到它:在检查下打断函数,然后使用SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED from Other session并查询表-新数据将已经存在。如果没有任何括号,这将不会产生您可能认为会产生的效果。
WHERE @DateEnd >= DateStart AND DateEnd >= @DateStart
WHERE
    @MyTableId <> MyTableId
    AND @DateEnd >= DateStart
    AND DateEnd >= @DateStart
WHERE
    @MyTableId <> MyTableId
    AND @DateEnd >= DateStart
    AND DateEnd >= @DateStart
    OR @DateEnd >= DateStart
    AND DateEnd is null
    OR @DateStart >= DateStart
    AND DateEnd is null