我正在为员工创建一个签到/签退系统。
有一个tbl_clockins,它包含每个打卡/打卡会话的记录,其中包含关于每个会话是否支付工资、员工在该会话中迟到了多长时间或他们加班了多少等信息。
还有一个名为tbl_user_work_settings的表格,经理可以在其中设置员工放假或因病休假的日期。
我正在创建一些报告,其中我需要每个员工的总计,例如,每个员工在给定日期范围内休假的总天数。我有一个非常长的查询,它实际上获得了所有需要的信息,但它很大,效率有点低。有没有办法让它变得更小/更高效?任何帮助都是非常感谢的。
// get total days worked, unpaid days, bank holidays, holidays, sicknesses
// and absences within given date range for given users
$sql = "SELECT us.username, daysWorked, secondsWorked,
unpaidDays, bankHolidays, holidays, sicknesses, absences
FROM
(SELECT username FROM users WHERE clockin_valid='1') us
LEFT JOIN (
SELECT username, selectedDate, count(isUnpaid) AS unpaidDays
FROM tbl_user_work_settings
WHERE isUnpaid = '1'
AND selectedDate>='$startDate'
AND selectedDate<='$endDate'
GROUP BY username
) u ON us.username=u.username
LEFT JOIN (
SELECT username, count(isBankHoliday) AS bankHolidays
FROM tbl_user_work_settings
WHERE isBankHoliday='1'
AND selectedDate>='$startDate'
AND selectedDate<='$endDate'
GROUP BY username
) bh ON us.username=bh.username
LEFT JOIN (
SELECT username, count(isHoliday) AS holidays
FROM tbl_user_work_settings
WHERE isHoliday='1'
AND selectedDate>='$startDate'
AND selectedDate<='$endDate'
GROUP BY username
) h ON us.username=h.username
LEFT JOIN (
SELECT username, count(isSickness) AS sicknesses
FROM tbl_user_work_settings
WHERE isSickness='1'
AND selectedDate>='$startDate'
AND selectedDate<='$endDate'
GROUP BY username
) s ON us.username=s.username
LEFT JOIN (
SELECT username, count(isOtherAbsence) AS absences
FROM tbl_user_work_settings
WHERE isOtherAbsence='1'
AND selectedDate>='$startDate'
AND selectedDate<='$endDate'
GROUP BY username
) a ON us.username=a.username
LEFT JOIN (
SELECT username, count(DISTINCT DATE(in_time)) AS daysWorked,
SUM(seconds_duration) AS secondsWorked
FROM tbl_clockins
WHERE DATE(in_time)>='$startDate'
AND DATE(in_time)<='$endDate'
GROUP BY username
) dw ON us.username=dw.username";
if(count($selectedUsers)>0)
$sql .= " WHERE (us.username='"
. implode("' OR us.username='", $selectedUsers)."')";
$sql .= " ORDER BY us.username ASC";发布于 2012-05-03 19:05:24
您可以在tbl_user_work_settings表的一次使用中使用SUM(condition):
// get total days worked, unpaid days, bank holidays, holidays, sicknesses
// and absences within given date range for given users
$sql = "
SELECT users.username,
SUM(ws.isUnpaid ='1') AS unpaidDays,
SUM(ws.isBankHoliday ='1') AS bankHolidays,
SUM(ws.isHoliday ='1') AS holidays,
SUM(ws.isSickness ='1') AS sicknesses,
SUM(ws.isOtherAbsence='1') AS absences,
COUNT(DISTINCT DATE(cl.in_time)) AS daysWorked,
SUM(cl.seconds_duration) AS secondsWorked
FROM users
LEFT JOIN tbl_user_work_settings AS ws
ON ws.username = users.username
AND ws.selectedDate BETWEEN '$startDate' AND '$endDate'
LEFT JOIN tbl_clockins AS cl
ON cl.username = users.username
AND DATE(cl.in_time) BETWEEN '$startDate' AND '$endDate'
WHERE users.clockin_valid='1'";
if(count($selectedUsers)>0) $sql .= "
AND users.username IN ('" . implode("','", $selectedUsers) . "')";
$sql .= "
GROUP BY users.username
ORDER BY users.username ASC";顺便说一句(也许对其他读者更有好处),我真的希望在将变量插入到之前,通过正确转义这些变量来避免SQL注入攻击。理想情况下,您根本不应该这样做,而应该将这样的变量作为预准备语句的参数传递给MySQL (不会对其进行计算):阅读有关Bobby Tables的更多信息。
另外,为什么要将整数类型作为字符串来处理(通过用单引号将它们括起来)?在MySQL中执行不必要的类型转换是不必要的,也是对资源的浪费。实际上,如果不同的isUnpaid等列都是0/1,您可以更改上面的内容,删除相等性测试,直接使用SUM(ws.isUnpaid)等。
发布于 2012-05-03 19:08:10
将每个要连接的表放入一个临时表中...然后在临时表的可接合字段上创建索引...并使用临时表进行查询。
示例:
SELECT username, selectedDate, count(isUnpaid) AS unpaidDays
INTO #TempTable1
FROM tbl_user_work_settings
WHERE isUnpaid = '1'
AND selectedDate>='$startDate'
AND selectedDate<='$endDate'
GROUP BY username
create clustered index ix1 on #TempTable1 (username)https://stackoverflow.com/questions/10429887
复制相似问题