比较两个日期范围时一个范围内有一个范围开始日期

问题描述:

我已经从这个拿到了下一个问题了:Comparing date ranges比较两个日期范围时一个范围内有一个范围开始日期

的解决方案,比较两个范围是查询:

SELECT * 从时间 WHERE NOT(RANGE_START> @check_period_end OR RANGE_END < @check_period_start)

我有额外的问题。我允许人们输入一段时间。准确地说,他们输入一个持续时间(即1周)和一系列开始日期(即5月的前2周),我必须找出他们指定的范围内是否有一周的时间段。

天真的解决方案是在我的范围内每天运行上述查询。因此 - 为了检查一个月内的3天插槽,我必须运行30个查询。有没有更高效的方法?

对于奖励积分 - 我正在使用Django。使用Django ORM有没有好的解决方案?

编辑 - 为了简化问题,我想我已经把它变成了另一个问题!我的实际问题是找到'自由空白'。我认为这会使下面的一些'纯SQL'方法无效。我认为这将是明智的start a new question而不是混淆这一个。其他人可能会发现这个问题对目前的形式有用。

由于用户没有在其标准中直接指定结束日期,因此问题比初看起来更简单。

SELECT * FROM periods p 
WHERE p.range_start >= @min_start 
AND p.range_start <= @max_start 
AND DATE_ADD(p.range_start, INTERVAL @duration DAY) <= p.range_end 

这不是SQL的好选择。

但是,在Django中,您可以从许多SQL约束中解脱出来。

首先,在您的模型中定义一个方法函数,以Python的方式执行您所需的操作。

例如

class MyThing(models.Model): 
    startDate = models.DateField(...) 
    duration = models.IntegerField(...) 
    def isInside(self, aDate, aDuration): 
     return aDate >= self.startDate and aDate+aDuration <= self.startDate+self.duration 

然后用你的isInside()方法资格的对象。这将在Python中完成一些工作,比在SQL中进行简单得多。

为这样的复杂查询定义自定义管理器。您将扩展基本的query_set方法以包含类似于此的逻辑。

for thing in MyThing.objects.filter(startDate__gte=aDate, startDate__lte=aDate+duration): 
    if thing.isInside(aDate, duration): 
     return thing 

这将使用SQL来获取对象的子集,其日期应包含您要查找的时间间隔。然后您可以从该列表中选择最终对象的间隔。

+0

想象一下,我正在一个月内检查3天。有什么比运行30个查询更好吗? (我会将这一点加入到原始问题中) – 2009-04-22 17:48:33

+0

我一直在跟踪你,直到你说:'得到一个接近的日期子集,然后从该列表中选择'。你能澄清吗? – 2009-04-22 18:10:55

+0

MyThing.objects.filter(startDate__gte = aDate,startDate__lte = aDate + duration)是应包含您要查找的范围的对象的子集。 – 2009-04-22 18:42:52

这个怎么样。

创建一个日期表,每个caledar日期一行。

SELECT * FROM CalendarDates cd 
    LEFT JOIN period p 
     ON cd.caldate > p.end_date 
     OR cd.caldate + duration < p.begin_date 

    WHERE p.period_id IS NULL 

幽州用户指定(举例来说):

  • 1周时间内
  • 开始日期(2009年5月1日)
  • 结束日期(2009年5月15日)


然后您声明您需要“找出是否有一周插槽在他们指定的范围内“。我不是100%肯定,如果我理解正确的,但是这是我从那个得到...

  • 没有“提供周期”(由开始/结束日期描述)
  • 的表您需要在与用户的开始/结束圈找到一个“avaialble期”释日期
  • 重叠必须持续至少1周(或任何时间,用户需要)


如果是这种情况下,我会按如下方式解决......

  • 找出重叠
  • 期间确定第一重叠日期
  • 确定最后的重叠日期
  • 如果这些日期间隔7天,这是一个比赛


我在SQL中的解决方案将...

SELECT 
    * 
FROM 
    periods 
WHERE 
    (range_start <= @check_end) 
    AND (range_end >= @check_start) 
    AND DATEDIFF(
      DAY, 
      CASE WHEN range_start > @check_start THEN range_start ELSE @check_start END, 
      CASE WHEN range_end < @check_end THEN range_end ELSE @check_end END 
     ) 
     >= @required_duration-1 


编辑

这是假设开始和结束日期被包容你的榜样逻辑暗示。
(2009年1月01日 - >'2009年1月01日')的一天期间)

我个人更喜欢开始日期包含,结束日期独家。
(为期一天的周期由“2009年1月01 repesented - >“2009年1月02”)

原因是,各种工科数学比较和操作变得更容易,而且也因为它不rquire读者假设你在工作的准确程度。

  • 如果按小时等级“2009年1月1日” - >“2009年1月1日”工作时间为1小时。
  • 但'2009年1月01日 - >'2009年1月2日'总是一天,如果你知道结束日期是独家。

在某些情况下,创建一个查询以获取您可能需要的所有数据,然后使用业务逻辑语言在测试之前对其进行过滤,结果会更快。

在我正在开发的应用程序中,通过滚动平均值进行类似的操作,可节省超过100倍。