【问题标题】:Finding Start and End date of a sequence in MySQL在 MySQL 中查找序列的开始和结束日期
【发布时间】:2014-03-02 13:43:56
【问题描述】:

所以我基本上有一张桌子,每个房间每天都有一个条目。我需要找到按该房间、属性和注释分组的所有连续日期的开始和结束日期。

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 日期子句之前就不会返回正确的开始日期等。

我们将不胜感激。

谢谢!

【问题讨论】:

  • 考虑提供适当的 DDL(和/或 sqlfiddle)以及所需的结果集
  • 分析大型“临时”数据集并不是 MySQL 的主要优势,我怀疑您不会轻易获得所需的性能。表格中没有其他可以提供帮助的信息,例如唯一的预订 ID?

标签: mysql date


【解决方案1】:

你想要的数据结构可以使用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);

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

【讨论】:

  • 嗯,我怀疑数据集并不能真正代表手头的问题。
【解决方案2】:

分析大型数据集并不是 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。注意 Fiddle 中的索引应该可以加快速度。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 2023-03-30
    • 1970-01-01
    • 2020-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多