2

我想知道从 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相同。)

更新:

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

示例:如何使用 mysql 获取两个给定日期之间的日期列表?

最初的想法是循环遍历每一行的时间范围内的每一天。然后对于每个时间范围,逐日从初始日期到结束日期,并返回每个时间范围(行)找到的星期几的列表。肯定不是一个快速的方法,但只是开始的一些东西。有什么比这个更好的建议或其他建议吗?

更新 2:

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

这是迄今为止我见过或见过的最直接且对性能影响最小的解决方案,但是我无法编辑表架构。

更新 3:

为了进一步澄清这个问题,万一有人感到困惑或误读。笔记:

我正在寻找可以在“开始”、“结束”处找到星期一或我在其时间范围内选择的另一个工作日(从“存在”到“结束”)的行,或沿着从“开始”到“结束”的时间段

更新 4:

在这里,您有这个问题的SQL Fiddle供您尝试您的想法,而无需在您的机器中构建表。

更新 5 - 解决方案:

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

如果您阅读本文并想尝试一下,看看它是否适合您的需求:

您可以使用这个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) 
        )
)
4

2 回答 2

1

There is no "good" way to do what you're asking with how your data is currently set up. An index cannot be used in this query since you cannot know which days are in the range until you read the two dates.

One possible way to improve the performance of the query would be to have an indicator field (something like TINYINT or CHAR(1)) for each day. It could help, but, in general, it might actually slow down the table due to the increased size and indexes. If you would only need to know if something happened on one or two days, this option could work, but the extra size would probably outweigh the benefits if you needed more than 2 or 3 days.

于 2013-01-11T17:32:20.877 回答
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) 
        )
    )  

这个绝对不快

于 2013-01-11T18:12:06.923 回答