我有一张表,其中包含员工访问控制的数据,不同行中办公室的入口和出口。
输出基于日期和时间范围示例中的查询
ac_date >= '2018-05-12' AND ac_date <= '2018-05-13' AND ac_time >='08:00:00' AND ac_time <= '13:00:00']
表格AC
CREATE TABLE `AC` (
`employee` int(11) NOT NULL,
`ac_date` date NOT NULL,
`ac_time` time NOT NULL,
`ac_event` tinyint(4) NOT NULL,
KEY `index2` (`employee`,`ac_date`,`ac_time`,`ac_event`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Employee ac_date ac_time ac_event
2032 2018-05-12 08:52:00 1
2032 2018-05-12 11:39:33 0
2032 2018-05-12 11:48:06 1
2032 2018-05-12 11:52:54 0
2032 2018-05-12 11:59:54 1
2032 2018-05-12 12:23:40 0
2032 2018-05-13 08:34:43 1
2032 2018-05-13 09:02:25 0
2032 2018-05-13 09:12:16 1
2032 2018-05-13 11:45:21 0
2032 2018-05-13 12:50:40 1
2032 2018-05-13 12:52:16 0
其中ac_ event = 1是输入,ac event = 0是输出。
我需要创建一个查询,显示同一行(进入/退出)中的数据,然后花时间让员工在办公室外停留。 EJ:
第一个块的输出:
Employee entry_date exit_date entry_date exit_date duration
2032 2018-05-12 2018-05-12 08:52:00 11:39:33 02:47:33
我能够通过使用相同的表执行查询来获得结果,但是我有重复的数据,因此我必须通过[ac_date,ac_time]求助于该组。我不知道我正在尝试的方式是否正确,所以我希望看到专家的解决方案。谢谢!
的更新
http://sqlfiddle.com/#!9/6f36f/3
答案 0 :(得分:2)
这是原始查询的简化版本:
select AC.employee, AC.ac_date, AC.ac_time,
min(AC2.ac_time) as exit_time,
timediff(min(AC2.ac_time), AC.ac_time)
from AC
left join AC as AC2
on AC2.ac_date = AC.ac_date
and AC2.ac_time > ac.ac_time
and AC2.ac_event = 0
where AC.ac_event = 1
AND AC.ac_date >= '2018-05-11'
AND AC.ac_date <= '2018-05-13'
AND AC.ac_time >= '00:00:00'
AND AC.ac_time <= '23:59:00'
group by AC.employee, AC.ac_date, AC.ac_time
order by AC.employee, AC.ac_date, AC.ac_time
;
请参阅fiddle
但无论你怎么写它,它总是一种非等连接(即不基于=
),如果没有匹配的索引,性能可能会很差。
顺便说一句,如果这是MariaDB或MySQL 8,那么LAG / LEAD将是一项简单的任务。
答案 1 :(得分:1)
试试这个:
SELECT
*,
TIMEDIFF(exit_time,entry_time) as duration
FROM
(
SELECT
Employee,
ac_date as entry_date,
ac_date as exit_date,
MIN(CASE WHEN ac_event=1 THEN ac_time END) entry_time,
MAX(CASE WHEN ac_event=0 THEN ac_time END) exit_time
FROM
AC
GROUP BY
Employee,
ac_date
) as t
答案 2 :(得分:1)
您可以使用相关子查询来获取进入/退出对:
SELECT employee, ac_date AS entry_date,
(SELECT ac_date
FROM AC AS i
WHERE i.ac_event = 0
AND i.employee = t.employee
AND i.ac_date >= t.ac_date
AND i.ac_time >= t.ac_time
ORDER BY i.ac_date, i.ac_time LIMIT 1) AS exit_date,
ac_time AS entry_time,
(SELECT ac_time
FROM AC AS i
WHERE i.ac_event = 0
AND i.employee = t.employee
AND i.ac_date >= t.ac_date
AND i.ac_time >= t.ac_time
ORDER BY i.ac_date, i.ac_time LIMIT 1) AS exit_time
FROM AC AS t
WHERE t.ac_date BETWEEN '2018-05-12' AND '2018-05-13' AND t.ac_event = 1;
<强>输出:强>
employee entry_date exit_date entry_time exit_time
-------------------------------------------------------
2032 2018-05-12 2018-05-12 08:52:00 11:39:33
2032 2018-05-12 2018-05-12 11:48:06 11:52:54
2032 2018-05-12 2018-05-12 11:59:54 12:23:40
2032 2018-05-13 2018-05-13 08:34:43 09:02:25
2032 2018-05-13 2018-05-13 09:12:16 11:45:21
2032 2018-05-13 2018-05-13 12:50:40 12:52:16
然后您可以使用TIMESTAMPDIFF来计算每个条目之间的时间 - 退出:
SELECT employee, entry_date, exit_date, entry_time, exit_time,
SEC_TO_TIME(TIMESTAMPDIFF(SECOND,
CONCAT(entry_date, ' ', entry_time),
CONCAT(exit_date, ' ', exit_time))) AS duration
FROM (
SELECT employee, ac_date AS entry_date,
(SELECT ac_date
FROM AC AS i
WHERE i.ac_event = 0
AND i.employee = t.employee
AND i.ac_date >= t.ac_date
AND i.ac_time >= t.ac_time
ORDER BY i.ac_date, i.ac_time LIMIT 1) AS exit_date,
ac_time AS entry_time,
(SELECT ac_time
FROM AC AS i
WHERE i.ac_event = 0
AND i.employee = t.employee
AND i.ac_date >= t.ac_date
AND i.ac_time >= t.ac_time
ORDER BY i.ac_date, i.ac_time LIMIT 1) AS exit_time
FROM AC AS t
WHERE t.ac_date BETWEEN '2018-05-12' AND '2018-05-13' AND t.ac_event = 1) AS x
答案 3 :(得分:0)
尝试这个:只需对每个条目employee, ac_date, ac_time
进行排序,然后在单独的集合中退出然后加入,这是一种可以使用{{1如果您希望记录同时包含入口和出口
INNER JOIN
以获得更好的性能
LEFT JOIN
答案 4 :(得分:0)
另一个选择是对同一个表使用双连接以获取退出记录:
SELECT t1.employee,
t1.ac_date AS entry_date,
t1.ac_time AS entry_time,
t2.ac_date AS exit_date,
t2.ac_time AS exit_time,
SEC_TO_TIME(TIMESTAMPDIFF(SECOND,
CONCAT(t1.ac_date, ' ', t1.ac_time),
CONCAT(t2.ac_date, ' ', t2.ac_time))) AS duration
/* fetches entry records */
FROM AC AS t1
/* fetches exit records that occur after the correlated entry record */
INNER JOIN AC AS t2
ON t1.employee = t2.employee AND t2.ac_event = 0
AND CONCAT(t1.ac_date, ' ', t1.ac_time) <= CONCAT(t2.ac_date, ' ', t2.ac_time)
/* fetches exit records that occur between t1, t2 records */
LEFT JOIN AC AS t3
ON t2.employee = t3.employee AND t3.ac_event = 0
AND CONCAT(t3.ac_date, ' ', t3.ac_time) >= CONCAT(t1.ac_date, ' ', t1.ac_time)
AND CONCAT(t3.ac_date, ' ', t3.ac_time) < CONCAT(t2.ac_date, ' ', t2.ac_time)
WHERE t1.ac_date BETWEEN '2018-05-12' AND '2018-05-13'
AND t1.ac_event = 1
AND t3.employee IS NULL /* There is no record between t1 entry and t2 exit */