如何将查询结果限制在每天的特定时间范围内?

时间:2014-08-05 13:36:29

标签: mysql sql utc

我有一个展示广告系列广告的应用。我将每个广告系列的广告组展示限制为每个广告系列的特定日期范围。我的"广告系列"表看起来像这样:

campaigns
  id : integer
  start_date : date
  end_date : date

我现在需要能够选择性地将广告系列广告的展示限制在每天的特定时间范围内。所以现在我的表看起来像

campaigns
  id : integer
  start_date : date
  end_date : date
  start_time : time, default: null
  end_time : time, default: null

所以我的[MySQL]查询看起来像这样:

SELECT
  ads.*
FROM
  ads
  INNER JOIN campaigns ON campaigns.id = ads.campaign_id
WHERE
  campaigns.start_date <= "2014-08-05" AND
  campaigns.end_date >= "2014-08-05" AND
  campaigns.start_time <= "13:30"
  campaigns.end_time >= "13:30";

(日期和时间实际上是使用当前日期/时间注入的。)

这很好用。但是,因为我以UTC时间存储start_time和end_time,所以有时end_time早于start_time;例如,在数据库中:

start_time = 13:00 (08:00 CDT)
end_time = 01:00 (20:00 CDT)

如何调整查询(甚至使用代码)来解决这个问题?

3 个答案:

答案 0 :(得分:3)

问题比看起来更难,因为广告系列比较时间范围可以超过日期边界。然后,还有一个复杂的问题。如果广告系列表示它一直运行到凌晨1点,那么结束日期是当前日期还是下一个日期?换句话说,就你的例子而言,2014-08-06凌晨1点应该算作2014-08-05。

我的建议是切换到当地时间。如果您的广告系列不会跨越午夜,那么这可以解决您的问题。

如果您只关心跨越午夜的广告系列,您可以执行以下操作:

WHERE campaigns.start_date <= '2014-08-05' AND
      campaigns.end_date >= '2014-08-05' AND
      ((campaigns.start_time <= campaigns.end_time and
        campaigns.start_time >= '13:00' and
        campaigns.end_time <= '18:00'
       ) or
       (campaigns.start_time >= campaigns.end_time and
        (campaigns.start_time >= '13:00' or
         campaigns.end_time <= '18:00'
        )
       )

请注意,当end_time大于开始时间时,您希望时间大于开始时间小于结束时间。在正常情况下,您希望时间大于开始时间小于结束时间。

如果你只关心比较时间段,你可以做类似的事情。将两者结合起来似乎相当复杂。

答案 1 :(得分:1)

你可以检查两种方式。

 SELECT
      ads.*
    FROM
      ads
      INNER JOIN campaigns ON campaigns.id = ads.campaign_id
    WHERE "2014-08-05" BETWEEN campaigns.start_date AND campaigns.end_date
      AND ("13:30" BETWEEN campaigns.start_time AND campaigns.end_time
        OR "13:30" BETWEEN campaigns.end_time AND campaigns.start_time)

如果您的范围是08:0016:00,则第一部分会找到您的结果而第二部分会找不到,因为范围错误。

如果您的范围是16:0008:00,则第一部分将找不到任何结果,第二部分会给您。

答案 2 :(得分:0)

所以,戈登林诺夫的回答让我朝着正确的方向前进。这是有效的查询:

SELECT
  ads.*
FROM
  ads
  INNER JOIN campaigns ON campaigns.id = ads.campaign_id
WHERE
    "2014-08-05" BETWEEN campaigns.start_date AND campaigns.end_date AND

    (campaigns.start_time IS NULL OR campaigns.end_time IS NULL) OR (
      ((campaigns.start_time < campaigns.end_time AND
        campaigns.start_time <= "13:30:00" AND campaigns.end_time >= "13:30:00") OR

       (campaigns.start_time > campaigns.end_time AND
        ((campaigns.start_time <= "13:30:00" AND campaigns.end_time <= "13:30:00") OR
         (campaigns.start_time >= "13:30:00" AND campaigns.end_time >= "13:30:00"))))
    );