在MySQL中查找序列的开始和结束日期

时间:2014-03-02 13:43:56

标签: mysql date

所以我基本上有一张桌子,每个房间每天有一个条目。我需要找到在该房间,财产和备注上分组的所有连续日的开始和结束日期。

property     room   date        notes
----------------------------------------------
2            101    2013-01-01  abc
2            101    2013-01-02  abc
2            101    2013-01-03  abc
2            101    2013-01-04  abc
2            101    2013-01-05  xyz
2            101    2013-01-06  xyz
2            101    2013-01-15  abc
2            101    2013-01-16  abc
2            101    2013-01-17  abc
2            107    2013-01-02  def
2            107    2013-01-03  def
2            109    2013-01-01  abc
2            109    2013-01-02  abc
3            101    2012-12-31  abc
3            101    2013-01-01  abc
3            101    2013-01-02  abc

我需要能够基于属性和日期查询它。当我按日期搜索时,我应该能够在序列的“开始日期”之后使用日期,并且仍然可以找到正确的开始日期。因此,如果我搜索说WHERE date ='2013-01-02'我应该返回类似的内容:

property   room   start_date      end_date    notes
----------------------------------------------------
2          101    2013-01-01      2013-01-04  abc
2          107    2013-01-02      2013-01-03  def
2          109    2013-01-01      2013-01-02  abc
3          101    2012-12-31      2013-01-02  abc

这将与一个相当大的表一起使用并返回数十万个结果,因此效率是主要关注点。我发现并试图将一些例子全部用于问题。如果它在WHERE日期条款之前,大多数都太慢,或者不会返回正确的开始日期等。

非常感谢任何帮助。

谢谢!

2 个答案:

答案 0 :(得分:0)

您可以使用group by

获取所需数据的结构
select property, room, min(date) as start_date, max(date) as end_date, notes
from table t
group by property, room, notes;

使用having子句获取特定日期的行:

select property, room, min(date) as start_date, max(date) as end_date, notes
from table t
group by property, room, notes
having date( '2013-01-02') between min(date) and max(date);

我不确定是否有更高效的方法,尽管这确实需要对整个表进行聚合。

答案 1 :(得分:0)

分析大型数据集并不是MySQL的强项,所以我怀疑你很难获得出色的性能。这个查询似乎可以解决手头的问题,但不一定是最快的;

SELECT r.property, r.room, 
       MAX(IF(rr.date<=r.date AND is_start, rr.date, NULL)) start_date, 
       MIN(IF(rr.date>=r.date AND is_end,   rr.date, NULL)) end_date, 
       r.notes
FROM rooms r
JOIN (SELECT r.*, IF(ry.room IS NULL, 1, 0) is_start,
                  IF(rt.room IS NULL, 1, 0) is_end
      FROM (SELECT *, DATE_SUB(date, INTERVAL 1 DAY) yesterday,
                      DATE_ADD(date, INTERVAL 1 DAY) tomorrow FROM rooms) r
      LEFT JOIN rooms ry 
        ON r.property=ry.property AND r.room=ry.room AND r.notes=ry.notes
       AND r.yesterday=ry.date
      LEFT JOIN rooms rt
        ON r.property=rt.property AND r.room=rt.room AND r.notes=rt.notes
       AND r.tomorrow=rt.date
      WHERE ry.room IS NULL OR rt.room IS NULL) rr
  ON r.property = rr.property AND r.room = rr.room AND r.notes = rr.notes
WHERE r.date = '2013-01-02'
GROUP BY r.property, r.room, r.notes

An SQLfiddle to test with。请注意小提琴中的索引应该加快速度。