2

我正在制作一个考勤系统,它包含一个介于两个日期之间的时间表,例如(晚上 10:00 到凌晨 3:00)。如何从 mysql 数据库中检索时间范围在 2 个日期之间的行?

我已经知道如何在 mysql 中使用 BETWEEN,我的问题是如何在不知道确切时间范围的情况下查询 mysql?因为它可能是任何东西(晚上 11:00 到凌晨 4:00)

我正在使用 3 个表: time_tbl:存储有关员工时间表的信息(例如晚上 10 点到凌晨 3 点) date_tbl:存储有关员工的日期安排的信息(例如星期一、星期二等) time_date_tbl:是一个连接表,时间和日期安排为从表 time_tbl 和 date_tbl 中获取的员工。

    time_tbl
    --------------------------------
    |  ID  |  Start    |  End      |
    --------------------------------
    |  1   |  22:00:00 |  03:00:00 |
    |  2   |  23:00:00 |  04:00:00 |
    |  3   |  08:00:00 |  11:00:00 |
    |  4   |  13:00:00 |  17:00:00 |
    --------------------------------

    date_tbl
    ---------------------
    |  ID  |  Days      |
    ---------------------
    |  1   |  Monday    |
    |  2   |  Tuesday   |
    |  3   |  Wednesday |
    ---------------------

    time_date_tbl
    -------------------------------------
    |  emp_id  |  time_id    |  date_id |
    -------------------------------------
    |  1       |  1          |  1       |
    |  1       |  1          |  2       |
    |  2       |  1          |  1       |
    |  3       |  3          |  1       |
    |  4       |  4          |  1       |
    |  4       |  1          |  1       |
    -------------------------------------

我想查询 mysql 以便检索数据(例如今天是星期一)我想检索日期等于今天“星期一”的记录,还包括晚上 10:00 到凌晨 3:00 的记录,其中晚上 10 点在星期天,星期一的前一天……

    desired result:
    -----------------------------------------------
    |  emp_id  |  time                 |  date    |
    -----------------------------------------------
    |  1       |  22:00:00 - 03:00:00  |  ?       | <-- started @ Sunday 10pm
    |  2       |  22:00:00 - 03:00:00  |  ?       | <-- started @ Sunday 10pm
    |  3       |  08:00:00 - 11:00:00  |  Monday  |
    |  4       |  13:00:00 - 17:00:00  |  Monday  | 
    |  4       |  22:00:00 - 03:00:00  |  ?       | <-- started @ Sunday 10pm
    -----------------------------------------------

mysql 中是否有某种“日期交叉器”函数/算法来完成这项工作?...

4

4 回答 4

2

感谢您使用更多信息更新问题。如果您想按天查询并返回时间范围...您的表格会使这有点复杂...

SELECT tdt.emp_id,CONCAT(DATE_FORMAT(tt.Start,'%H:%m:%s'),' - ',DATE_FORMAT(tt.End,'%H:%m:%s')),dt.Days
FROM time_date_tbl tdt INNER JOIN date_tbl dt ON (tdt.date_id=dt.`ID`) INNER JOIN time_tbl tt ON (tt.`ID`=tdt.time_id)
WHERE dt.ID=1

现在我在上面没有看到的是一个带有日期的实际日期字段......换句话说,上面的查询将列出所有星期一......永远。您可能需要向 WHERE 部分添加更多内容以对其进行更多限制。

现在,如果这是一个较新的项目并且您仍然有能力重组......如果 time_tbl 是一个带有两个日期的 id - 一个开始日期时间和一个结束日期时间,那么您真的不需要其余的表:

SELECT emp_id,CONCAT(DATE_FORMAT(tt.Start,'%H:%m:%s'),' - ',DATE_FORMAT(tt.End,'%H:%m:%s'))
FROM time_tbl tt
WHERE (DATE_FORMAT('%w',tt.Start)=1) OR (DATE_FORMAT('%w',tt.End)=1)

这将再次列出所有星期一。您可以添加到 where 以进一步限制它。

于 2013-01-26T20:05:14.990 回答
1

尝试这个:

WHERE scheduleStartDate >= givenStartDate
     AND scheduleEndDate <= givenEndDate
于 2013-01-26T20:05:34.447 回答
1

一个例子。

DROP TABLE IF EXISTS `datetime`;

CREATE TABLE `datetime` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `datetime` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `datetime` (`id`, `datetime`)
VALUES
    (1,'2013-01-27 08:00:00'),
    (2,'2013-01-27 10:00:00'),
    (3,'2013-01-27 12:00:00'),
    (4,'2013-01-27 13:00:00');

select * from `datetime` where `datetime` >= '2013-01-27 10:00:00' and `datetime` <= '2013-01-27 12:00:00'

-- results
2   2013-01-27 10:00:00
3   2013-01-27 12:00:00
于 2013-01-26T20:06:07.003 回答
0

主要问题是没有时间间隔可供搜索。

以下代码创建要搜索的内部时间间隔。

DROP VIEW IF EXISTS    `time_view` ;
DROP VIEW IF EXISTS    `employee_schedule_view` ;
DROP TABLE IF EXISTS `employee_schedule`;
DROP TABLE IF EXISTS `day`;   
DROP TABLE IF EXISTS `time`;

CREATE TABLE `time` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `employee_id` int(11) unsigned NOT NULL,
  `start_time` time DEFAULT NULL,
  `hours` int(11) DEFAULT '0',
  `minutes` int(11) DEFAULT '0',
  `seconds` int(11) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `time` (`id`, `employee_id`, `start_time`, `hours`, `minutes`, `seconds`)
VALUES
    (1,1,'22:00:00',5,0,0),
    (2,2,'23:00:00',5,0,0),
    (3,3,'08:00:00',3,0,0),
    (4,4,'13:00:00',4,0,0),
    (5,5,'17:00:00',24,0,0),
    (6,6,'23:00:00',26,0,0);

/* create a time view that contains interval information */
create or replace view time_view as 
select 
    id as time_id
,    start_time
-- calculate the time interval
,   SEC_TO_TIME( hours * 3600 +  minutes * 60  + seconds ) `interval`
-- calculate the time if we assume time is contiguous
,    SEC_TO_TIME( ( hour(start_time) + hours ) * 3600 + ( minute(start_time) + minutes) * 60 + second(start_time) + seconds ) contiguous_time
-- modulate to the number of seconds in a day to get the end time suitable for humans to read
,  SEC_TO_TIME((( hour(start_time) + hours ) * 3600 + ( minute(start_time) + minutes) * 60 + second(start_time) + seconds ) % 86400 ) end_time
,  floor( (( hour(start_time) + hours ) * 3600 + ( minute(start_time) + minutes) * 60 + second(start_time) + seconds ) / 86400 ) dayOffset
from `time` ;

CREATE TABLE `day` (
  `id` int(11) unsigned NOT NULL,
  `name` varchar(15) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `day` (`id`, `name`)
VALUES
    (0,'Monday'),
    (1,'Tuesday'),
    (2,'Wednesday'),
    (3,'Thursday'),
    (4,'Friday'),
    (5,'Saturday'),
    (6,'Sunday');


CREATE TABLE `employee_schedule` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `employee_id` int(11) unsigned NOT NULL,
  `time_id` int(11) unsigned NOT NULL,
  `day_id` int(11) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `time_id` (`time_id`),
  KEY `day_id` (`day_id`),
  CONSTRAINT `employee_schedule_ibfk_2` FOREIGN KEY (`day_id`) REFERENCES `day` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `employee_schedule_ibfk_1` FOREIGN KEY (`time_id`) REFERENCES `time` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `employee_schedule` (`id`, `employee_id`, `time_id`, `day_id`)
VALUES
    (1,1,1,0),
    (2,1,1,1),
    (3,2,1,0),
    (4,3,3,0),
    (5,4,4,0),
    (6,4,1,0),
    (7,5,1,5),
    (8,4,5,6),
    (9,3,6,6),
    (10,6,6,1);

/* create an employee view that has interval information */
create or replace view employee_schedule_view as
select  schedules.id schedules_id
, employee_id
, day_id as start_day_id
, start_days.name as start_day_name
, `start_time`
, `interval`
, `contiguous_time`
, `end_time`
, `end_days`.`id` as end_day_id
, `end_days`.name as end_day_name
-- some starting point - note the date is incorrect - it is merely here to define a starting point of the interval
,  timestamp( concat( date_format( date_add( date( now() ), interval `day_id` day ), '%Y-%m-%d' ) , ' ' , start_time )) `internal_start`
-- some ending point - note the date is incorrect - it is merel here to define an ending point of the interval
,  addtime( timestamp( concat( date_format( date_add( date( now() ), interval `day_id` day ), '%Y-%m-%d' ) , ' ' , `start_time` )) , `interval` ) `internal_finish`
from `employee_schedule` `schedules`
inner join `day` `start_days`
on `schedules`.`day_id` = `start_days`.id
inner join `time_view` `times`
on `schedules`.`time_id` = `times`.`time_id`
inner join `day` `end_days`
-- use mod to allow for instance when the start day is 'after' the end day -- think about sunday
on `end_days`.`id` = ( `start_days`.id + `times`.dayOffset ) % 7

一旦支持间隔,就可以轻松运行以下 sql ...并理解。

-- example
-- find who is working at 11:00 on a Wednesday
set @dayID := 2 ;
set @time := '11:00:00' ;
select employee_schedule_view.schedules_id
, employee_schedule_view.employee_id
, employee_schedule_view.start_day_name
, employee_schedule_view.start_time
, employee_schedule_view.interval
, employee_schedule_view.end_time
, employee_schedule_view.end_day_name
from `employee_schedule_view` 
inner join
(
    select concat( date_format( date_add( date(now()), interval @dayID day ), '%Y-%m-%d' ), ' ', @time) internal_check
) internal_check
where 
internal_check.internal_check >= internal_start
and internal_check.internal_check <= internal_finish 
;

-- find who is working at 23:00 on a Monday
set @dayID := 0 ;
set @time := '23:00:00' ;
select employee_schedule_view.schedules_id
, employee_schedule_view.employee_id
, employee_schedule_view.start_day_name
, employee_schedule_view.start_time
, employee_schedule_view.interval
, employee_schedule_view.end_time
, employee_schedule_view.end_day_name
from `employee_schedule_view` 
inner join
(
    select concat( date_format( date_add( date(now()), interval @dayID day ), '%Y-%m-%d' ), ' ', @time) internal_check
) internal_check
where 
internal_check.internal_check >= internal_start
and internal_check.internal_check <= internal_finish 
;

-- example results
1   1   Monday  22:00:00    05:00:00    03:00:00    Tuesday
3   2   Monday  22:00:00    05:00:00    03:00:00    Tuesday
6   4   Monday  22:00:00    05:00:00    03:00:00    Tuesday
于 2013-01-27T06:33:38.533 回答