i have 3 tables
Employee => e_id (PK), dep_id (Fk)
Department => d_id (PK)
Attendance => id (PK), date_of_absence (DATE), e_id_f (FK)
i want to get the number of absent employees in certain department for a certain period.
i created a table called MyDates
CREATE TABLE MyDates (mydate date);
and this procedure to fill MyDates Table with Dates
CREATE PROCEDURE filldates(dateStart DATE, dateEnd DATE)
BEGIN
WHILE dateStart <= dateEnd DO
INSERT INTO MyDates (mydate) VALUES (dateStart);
SET dateStart = date_add(dateStart, INTERVAL 1 DAY);
END WHILE;
END;
then i called the procedure to fill MyDates with date CALL filldates('2017-01-01','2017-03-31');
Then i made this select statement :
select mydates.mydate, count(attendance.date_of_absence)
from mydates left join attendance on
mydates.mydate = attendance.date_of_absence
where mydates.mydate Between "2017-01-01" AND "2017-01-31"
group by mydates.mydate
This query gets what i need but for all departments, BUT for a certain department the number of rows is incorrect
select mydates.mydate, count(attendance.date_of_absence)
from mydates
left join attendance on mydates.mydate = attendance.date_of_absence
inner join employee on attendance.e_id_f = employee.e_id
where mydates.mydate Between "2017-01-01" AND "2017-01-31" AND employee.dep_id = 4
group by mydates.mydate;
This is a screenshot IMG
There are 3 issues with your query I can see. The 1st 2 results in dropping the dates where no matching record is found, the 3rd potentially means that you get wrong counts:
inner join employee on attendance.e_id_f = employee.e_id
- if there is no matching record for a day, then attendance.e_id_f
will be null for that day. The inner join will eliminate this record from the resultset. Solution: make this join a left as well.
AND employee.dep_id = 4
- this would only keep records in the resultset, that have an employee record associated with it, so if you have a day with 0 absences, this criteria would eliminate it from the resultset. Solution: include this criteria in the join condition.
count(attendance.date_of_absence)
- counts occurances from the attendance table, which will not be correct after adding the 2nd left join. Solution: use count(employee.dep_id)
instead.
Modified query:
select mydates.mydate, count(employee.dep_id)
from mydates
left join attendance on mydates.mydate = attendance.date_of_absence
left join employee on attendance.e_id_f = employee.e_id AND employee.dep_id = 4
where mydates.mydate Between "2017-01-01" AND "2017-01-31" group by mydates.mydate
Alternative solution is to use nested joins, where you specifically instruct MySQL to execute attendance inner join employee
join first. You still need to move the employee.dep_id = 4
condition to the join condition:
select mydates.mydate, count(attendance.date_of_absence)
from mydates
left join (attendance inner join employee)
on mydates.mydate = attendance.date_of_absence
and attendance.e_id_f = employee.e_id
and employee.dep_id = 4
where mydates.mydate Between "2017-01-01" AND "2017-01-31"
group by mydates.mydate
In the latter case the nested inner join ensures that only those attendance records are returned that belong to dep_id = 4
and these records are then left joined to your dates table. In this case there is no need to change the field you are counting.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.