我们这里有一个名为attendance_log
的表,该表捕获了登录和注销时间,我正在使用查询来准确获取和计算工作时间。我提出的查询实际上效果很好,但是我想知道是否有一种方法可以缩短某些部分。以下是我查询的基础:
不幸的是,我的雇主仍在使用MySQL 4.1,所以..
SELECT staffid,DATE(CHECKINOUT) AS dci,
MIN(TIME(CHECKINOUT)) atin,
CASE WHEN MIN(TIME(CHECKINOUT)) <= '08:30:59' THEN '08:30:00'
WHEN MIN(TIME(CHECKINOUT)) BETWEEN '08:31:00' AND '09:00:59' THEN '09:00:00'
WHEN MIN(TIME(CHECKINOUT)) BETWEEN '09:01:00' AND '09:30:59' THEN '09:30:00'
WHEN MIN(TIME(CHECKINOUT)) BETWEEN '09:31:00' AND '10:00:59' THEN '10:00:00'
WHEN MIN(TIME(CHECKINOUT)) BETWEEN '10:01:00' AND '10:30:59' THEN '10:30:00'
WHEN MIN(TIME(CHECKINOUT)) BETWEEN '10:31:00' AND '11:00:59' THEN '11:00:00'
WHEN MIN(TIME(CHECKINOUT)) BETWEEN '11:01:00' AND '11:30:59' THEN '11:30:00'
WHEN MIN(TIME(CHECKINOUT)) BETWEEN '11:31:00' AND '12:00:59' THEN '12:00:00'
WHEN MIN(TIME(CHECKINOUT)) BETWEEN '12:01:00' AND '12:30:59' THEN '12:30:00'
WHEN MIN(TIME(CHECKINOUT)) BETWEEN '12:31:00' AND '13:00:59' THEN '13:00:00'
END AS Time_IN,
MAX(TIME(CHECKINOUT)) AS atout,
CASE
WHEN MAX(TIME(CHECKINOUT)) <= '08:59:59' THEN '08:30:00'
WHEN MAX(TIME(CHECKINOUT)) <= '09:29:59' THEN '09:00:00'
WHEN MAX(TIME(CHECKINOUT)) <= '09:59:59' THEN '09:30:00'
WHEN MAX(TIME(CHECKINOUT)) <= '10:29:59' THEN '10:00:00'
WHEN MAX(TIME(CHECKINOUT)) <= '10:59:59' THEN '10:30:00'
WHEN MAX(TIME(CHECKINOUT)) <= '11:29:59' THEN '11:00:00'
WHEN MAX(TIME(CHECKINOUT)) <= '11:59:59' THEN '11:30:00'
WHEN MAX(TIME(CHECKINOUT)) <= '12:29:59' THEN '12:00:00'
ELSE MAX(TIME(CHECKINOUT))
END AS Time_OUT,
DAYNAME(CHECKINOUT) AS dname,
GROUP_CONCAT(TIME(checkinout) ORDER BY TIME(checkinout) SEPARATOR ' ') allci,COUNT(*) cnt
FROM attendance_log,
(SELECT @nday:=28800, @hday:=16200, @rtime:=3600) v
WHERE staffid='HS078'
AND MONTH(checkinout)=MONTH(CURDATE()-INTERVAL 1 MONTH)
AND YEAR(checkinout)=YEAR(CURDATE())
GROUP BY DATE(CHECKINOUT);
如您所见,CASE
表达式中有太多操作无法同时获得Time_IN
和Time_OUT
值。我最近发现了更多有关在MySQL中使用变量的信息,但现在我将其用于其他功能,但不在此查询中。
我在这里准备了一个小提琴,查询的时间比我上面给出的示例长得多{= {3}}
所以我的问题是,如何缩短CASE
表达式中的条件?也许我定义了第一个“有效时间”值,然后像这样每30分钟运行一次间隔?
编辑:
我设法通过“人为地”创建分钟和秒,同时增加1小时的登录时间并保留从记录中提取的注销时间来缩短查询时间;
SELECT staffid,
DATE(CHECKINOUT) AS dci,
DAYNAME(CHECKINOUT) AS dname,
MIN(TIME(CHECKINOUT)) atin,
CASE WHEN MIN(TIME(checkinout)) < '08:30:59' THEN '08:30:00'
WHEN MIN(TIME(checkinout)) > '08:30:59' THEN
CONCAT_WS(':',CASE WHEN MINUTE(MIN(TIME(checkinout))) > 30 THEN LPAD(HOUR(MIN(checkinout))+1,2,'0')
WHEN MINUTE(MIN(TIME(checkinout))) <= 30 THEN LPAD(HOUR(MIN(checkinout)),2,'0')END,
CASE WHEN MINUTE(MIN(TIME(checkinout))) > 30 THEN '00'
WHEN MINUTE(MIN(TIME(checkinout))) <= 30 THEN 30 END,'00') END tin,
MAX(TIME(CHECKINOUT)) AS atout,
CASE WHEN COUNT(*)=4 AND MAX(TIME(checkinout)) < '18:00:00' THEN '17:30:00'
WHEN COUNT(*)=2 AND DAYNAME(checkinout)='Saturday' AND MAX(TIME(checkinout)) > '13:00:00' THEN '13:00:00'
WHEN COUNT(*) IN (0,1,3) THEN 'Incomplete'
ELSE CONCAT_WS(':',LPAD(HOUR(MAX(checkinout)),2,'0'),CASE WHEN MINUTE(MAX(TIME(checkinout))) < 30 THEN '00'
WHEN MINUTE(MAX(TIME(checkinout))) >= 30 THEN 30 END,'00') END tout,
GROUP_CONCAT(TIME(checkinout) ORDER BY TIME(checkinout) SEPARATOR ' ') allci,COUNT(*) cnt
FROM attendance_log, (SELECT @nday:=28800, @hday:=16200, @rtime:=3600) v
WHERE staffid='HS078'
AND MONTH(checkinout)=MONTH(CURDATE())
AND YEAR(checkinout)=YEAR(CURDATE())
GROUP BY DATE(CHECKINOUT);
这个想法非常简单,无论员工是否在上午8:30之前登录,查询都将在上午8:30捕获,一旦超过该时间一分钟,将被视为延迟30分钟。但是,如果注销时间假设是下午05:30,则需要有30分钟的确切间隔才能被捕获为超时。例如:
额外:
答案 0 :(得分:0)
在使用@Barmar建议进行了一些测试之后,我发现他的方法比我尝试过的任何方法都要短:
SELECT A.*,
CASE WHEN MIN(timechk) <= @chkin THEN @chkin
ELSE CEIL(MIN(timechk)/1800)*1800 END AS tin -- here I used @Barmar suggestion,
MAX(timechk) atout,
COUNT(*) AS cnt,
GROUP_CONCAT(timechk ORDER BY timechk SEPARATOR ' ') timelist FROM
(SELECT staffid,DATE(CHECKINOUT) AS dci,checkinout,
DAYNAME(CHECKINOUT) AS dname,
TIME_TO_SEC(checkinout) AS timechk
FROM att_log
WHERE staffid='HF002'
AND MONTH(checkinout)=MONTH(CURDATE()-INTERVAL 1 MONTH)
AND YEAR(checkinout)=YEAR(CURDATE())) A,
(SELECT @nday:=28800,@hday:=16200,@anhour:=3600,@chkin:=30600,@chkout:=63000,@min30:=1800) v
GROUP BY dci;
当然,我仍然需要手动执行许多操作,但是就基本查询而言,与之前的查询尝试相比,这满足了我的需求。