[英]How to get record in mysql that has a time in between two dates?
我正在制作一個考勤系統,它包含一個時間表,該時間表介於兩個日期之間,例如(晚上10:00到凌晨3:00)。 如何從mysql數據庫中具有兩個日期之間的時間范圍的行檢索?
我已經知道如何在MySQL中使用BETWEEN,我的問題是如何在不知道確切時間范圍的情況下查詢mysql? 因為可能是這樣(可能是晚上11:00到4:00 am)
我正在使用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,其中10pm是星期日,星期一的前一天...
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中是否有某種“ Date Crosser”函數/算法來完成這項工作?
感謝您使用更多信息更新問題。 如果您想按天查詢並返回時間范圍...您的表格會使這變得有些復雜...
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 scheduleStartDate >= givenStartDate
AND scheduleEndDate <= givenEndDate
一個例子。
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
主要問題是沒有搜索時間間隔。
以下代碼創建了要搜索的內部時間間隔。
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.