检索其存储的时间范围具有给定工作日的一次或多次出现的行

时间:2013-01-11 16:42:33

标签: mysql innodb

我想知道从MySQL表中检索行的最佳方式(性能),其中两个日期类型字段一起组成一个给定的时间范围,恰好在相关时间范围内的某个某一周工作日

假设给定的表结构和数据示例,那么检索所存储的时间帧恰好具有一个或多个星期一的所有行的最佳方法是,例如,星期一由数字2引用。

Table: ExampleA
Fields:
ID (int) | Begin (date) | End (date)
------------------------------------
1        |  2012-02-14  | 2012-02-16
2        |  2012-01-01  | 2012-01-15
3        |  2012-03-04  | 2012-03-06
4        |  2012-01-23  | 2012-02-07
5        |  2012-07-15  | 2012-07-15
6        |  2012-03-06  | 2012-03-13

在示例查询中,最好通过基于非零的索引来引用给定的工作日,从周日结束于星期六开始,分别构成以下索引位置:1到7。 (与MySQL函数DAYOFWEEK相同。)

更新

一直在考虑如何在给定的时间范围内逐日迭代并且看起来不太好。创建临时表等的要求,不实用,当同时用户请求具有相同要求的操作时,会导致问题。

示例:How can I get a list of dates between two given dates with mysql?

最初的想法是遍历每一行时间范围的每一天。然后,对于每个时间帧,每天都要经过初始日期到结束日期,并返回每个时间范围(行)找到的工作日的列表。肯定不是一个快速的方式,但只是一些入门。任何建议或其他建议比这更好吗?

更新2:

G-Nugget suggested每周为每个星期创建一个布尔字段,并且在添加新行时,为所述行的时间范围内找到的工作日标记相应的字段为true。当然,这是由使用数据库的应用程序完成的,而不是SQL查询本身。

这是我迄今为止看到的最简单,性能最差的解决方案,但我无法编辑表架构。

更新3:

更多地澄清这个问题,如果有人感到困惑或误读了它。注意:

  

我正在寻找可以找到工作日的行   星期一或我选择他们时间某个地方的另一个星期   框架(从“存在”到“结束”),在“开始”,“结束”或沿着时间段   范围从“开始”到“结束”

更新4:

在这里,您有SQL Fiddle这个问题可以让您尝试自己的想法,而无需在机器中构建表格。

更新5 - 解决方案:

使用Alexey Gerasimov answer我能够将他的where子句逻辑应用于我自己的问题并完成我的解决方案。谢谢Alexey。

如果您正在阅读本文并希望尝试并查看它是否符合您的需求:

您可以使用此SQLFiddle或此小查询来设置并运行其解决方案:

# Create table
CREATE TABLE `ExampleA` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Begin` date NOT NULL,
  `End` date NOT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1;

# Insert demo data
INSERT INTO `ExampleA`(`ID`,`Begin`,`End`) VALUES  
(1,'2012-02-14','2012-02-16'),
(2,'2012-01-01','2012-01-15'),
(3,'2012-03-04','2012-03-06'),
(4,'2012-01-23','2012-02-07'),
(5,'2012-07-15','2012-07-15'),
(6,'2012-03-06','2012-03-13');

# Query to retrieve rows which time frame
# has one or more occurrences of a given weekday
#
# 1 Sunday
# 2 Monday
# 3 Tuesday
# 4 Wednesday
# 5 Thursday 
# 6 Friday
# 7 Saturday

SET @MYDAYOFWEEK=2;
SELECT * FROM ExampleA
WHERE
(
        ( @MYDAYOFWEEK >= DAYOFWEEK(BEGIN) AND @MYDAYOFWEEK <= DAYOFWEEK(BEGIN) + DATEDIFF(END,BEGIN) )
    OR  
        ( 
          @MYDAYOFWEEK+7 >= DAYOFWEEK(BEGIN) AND @MYDAYOFWEEK+7 <= DAYOFWEEK(BEGIN) + DATEDIFF(END,BEGIN) 
        )
)

2 个答案:

答案 0 :(得分:1)

没有“好”的方法可以解决您当前如何设置数据的问题。索引不能在此查询中使用,因为在您阅读这两个日期之前,您无法知道该范围中的哪些天数。

提高查询性能的一种可能方法是每天都有一个指标字段(类似TINYINTCHAR(1))。 可以帮助,但是,通常,由于大小和索引的增加,它实际上可能会减慢表的速度。如果您只需要知道在一两天内发生了什么事情,这个选项就可以运行,但如果您需要超过2或3天,额外的大小可能会超过好处。

答案 1 :(得分:1)

这样的事情怎么样:

select * from ExampleA
where ID = MYDAYOFWEEK
and (
        ( id >= dayofweek(begin) and id <= dayofweek(begin) + DATEDIFF(end,begin) )
    OR  
        ( 
        id+7 >= dayofweek(begin) and id+7 <= dayofweek(begin) + DATEDIFF(end,begin) 
        )
    )   

第一次检查与同一周的日期匹配,第二次检查与周数相匹配。不确定这是否是性能最佳的查询

<强>更新

对不起。我认为第一列是一周的日期。要修复,只需更改查询,如下所示:

select * from ExampleA
where (
        ( MYDAYOFWEEK >= dayofweek(begin) and MYDAYOFWEEK <= dayofweek(begin) + DATEDIFF(end,begin) )
    OR  
        ( 
        MYDAYOFWEEK+7 >= dayofweek(begin) and MYDAYOFWEEK+7 <= dayofweek(begin) + DATEDIFF(end,begin) 
        )
    )  

这个绝对不是快速的