当前位置: 首页 > 面试题库 >

使用SQL查找有冲突的日期间隔

梅耘豪
2023-03-14
问题内容

假设我在Sql Server 2008中具有下表:

ItemId StartDate   EndDate
1      NULL        2011-01-15
2      2011-01-16  2011-01-25
3      2011-01-26  NULL

如您所见,该表具有StartDate和EndDate列。我想验证这些列中的数据。间隔不能相互冲突。因此,上面的表是有效的,但是下一个表是无效的,因为第一行的结束日期大于第二行的StartDate。

ItemId StartDate   EndDate
1      NULL        2011-01-17
2      2011-01-16  2011-01-25
3      2011-01-26  NULL

NULL 在这里表示无穷大。

您能帮我写一个脚本进行数据验证吗?

[第二项任务]

感谢您的回答。我很复杂。假设我有这样的表:

ItemId  IntervalId StartDate   EndDate
1       1          NULL        2011-01-15
2       1          2011-01-16  2011-01-25
3       1          2011-01-26  NULL
4       2          NULL        2011-01-17
5       2          2011-01-16  2011-01-25
6       2          2011-01-26  NULL

在这里,我想验证一组中的间隔IntervalId,但不验证整个表中的间隔。因此,间隔1将是有效的,但是间隔2将是无效的。

并且。可以在表中添加约束以避免此类无效记录吗?

[最终解决方案]

我创建了一个函数来检查间隔是否冲突:

CREATE FUNCTION [dbo].[fnIntervalConflict]
(
    @intervalId INT,
    @originalItemId INT,
    @startDate DATETIME,
    @endDate DATETIME
)
RETURNS BIT
AS
BEGIN

    SET @startDate = ISNULL(@startDate,'1/1/1753 12:00:00 AM')
    SET @endDate = ISNULL(@endDate,'12/31/9999 11:59:59 PM')

    DECLARE @conflict BIT = 0

    SELECT TOP 1 @conflict = 1
    FROM Items
    WHERE IntervalId = @intervalId
    AND ItemId <> @originalItemId
    AND (
    (ISNULL(StartDate,'1/1/1753 12:00:00 AM') >= @startDate 
     AND ISNULL(StartDate,'1/1/1753 12:00:00 AM') <= @endDate)
     OR (ISNULL(EndDate,'12/31/9999 11:59:59 PM') >= @startDate 
     AND ISNULL(EndDate,'12/31/9999 11:59:59 PM') <= @endDate)
    )

    RETURN @conflict
END

然后我在表中添加了2个约束:

ALTER TABLE dbo.Items ADD CONSTRAINT
    CK_Items_Dates CHECK (StartDate IS NULL OR EndDate IS NULL OR StartDate <= EndDate)

GO

ALTER TABLE dbo.Items ADD CONSTRAINT
    CK_Items_ValidInterval CHECK (([dbo].[fnIntervalConflict]([IntervalId], ItemId,[StartDate],[EndDate])=(0)))

GO

我知道,第二个约束减慢了插入和更新操作的速度,但这对我的应用程序不是很重要。而且,现在我可以fnIntervalConflict在插入和更新表中的数据之前从应用程序代码中调用函数。


问题答案:
declare @T table (ItemId int, IntervalID int, StartDate datetime,   EndDate datetime)

insert into @T
select 1, 1,  NULL,        '2011-01-15' union all
select 2, 1, '2011-01-16', '2011-01-25' union all
select 3, 1, '2011-01-26',  NULL        union all
select 4, 2,  NULL,        '2011-01-17' union all
select 5, 2, '2011-01-16', '2011-01-25' union all
select 6, 2, '2011-01-26',  NULL

select T1.*
from @T as T1
  inner join @T as T2
    on coalesce(T1.StartDate, '1753-01-01') < coalesce(T2.EndDate, '9999-12-31') and
       coalesce(T1.EndDate, '9999-12-31') > coalesce(T2.StartDate, '1753-01-01') and
       T1.IntervalID = T2.IntervalID and
       T1.ItemId <> T2.ItemId

结果:

ItemId      IntervalID  StartDate               EndDate
----------- ----------- ----------------------- -----------------------
5           2           2011-01-16 00:00:00.000 2011-01-25 00:00:00.000
4           2           NULL                    2011-01-17 00:00:00.000


 类似资料:
  • 问题内容: 我正在管理事件数据库。每个事件都有开始和结束时间戳记()。 目前,我可以通过一个SQL查询执行以下操作: 建立日历,并记下发生事件的日期 列出给定日期(YYYY / MM / DD,YYYY / MM)中发生的事件 问题是当一个事件跨越几天时,我无法在它的开始和结束时间戳之间的日期列出它。 例如: 活动开始于2011/05/25和结束于2011/05/27,但我无法在页面2011/05

  • 问题内容: 我有一个包含2个字段的表:唯一ID,用户ID(外键)和日期时间。这是对服务的访问日志。我在SQL Server中工作,但我希望得到不可知论的答案。 我想使用SQL为最长间隔开始的特定用户查找ID。 因此,举例来说,假设我的值如下(为一位用户简化): 如果我搜索用户1的最长间隔,我将得到ID 2(也可以在那儿获得间隔的长度,但不那么关键)。 在SQL中最有效的方法是什么? 注意:ID不一

  • 问题内容: 首先,感谢任何帮助我解决此问题的人。我正在使用SQL 2005,但如果05中没有可用的解决方案,则可以使用2008。 我有一排数据看起来像这样: 因此,我要做的是每天计算每个区域的总请求量。结果应为: 我该怎么做呢?我很沮丧,没有任何谷歌搜索帮助。 问题答案: 您将需要一个Calendar表,或者可以使用CTE生成一个。一旦有了这些,其余的查询就应该变得无关紧要了。由于递归问题并且不允

  • 问题内容: 我有一列的数据像 我需要编写一个SQL查询/过程,这将有助于我获取日期之间差异的平均值。对于上面的示例,它将是 (19 + 8 + 10)/3=12.33。 请提供帮助。 在此先感谢Geetha 问题答案: 我不知道您的RDBMS,但这是来自SQL Server。另外,您的计算之一是错误的-02/09/2011-13/08/2011是20,而不是19。 产生的结果是12.667:(20

  • 问题内容: 我有一张可以容纳一年中所有天/月的表 例如 我有一张表格,显示来自不同数据集的日期范围 例如 我如何比较这两个表以显示该特定月份的数据集中缺少哪些日期 对于上面示例中的数据集所在的示例,EG缺少日期范围01/09/2013-19/09/2013 谢谢你的帮助! 问题答案: 您可以使用CTE并通过以下方式编写查询:

  • 问题内容: 当我尝试执行此代码时,在“ with DateDimension”行出现错误: 消息206,级别16,状态2,第15行 操作数类型冲突:日期与int不兼容 这是我正在使用的SQL查询: 问题答案: 您的问题在于该部分。尝试使用,如下所示: 编辑:我不知道您的原始代码是否要使用该选项,但是如果您不知道我建议您阅读此内容。基本上,在这种情况下,这意味着您可以使用CTE列出1,000个日期。