简体   繁体   English

MYSQL左联接和内联接

[英]MYSQL left join and inner join

i have 3 tables 我有3张桌子

Employee => e_id (PK), dep_id (Fk) 员工=> e_id(PK),dep_id(Fk)

Department => d_id (PK) 部门=> d_id(PK)

Attendance => id (PK), date_of_absence (DATE), e_id_f (FK) 出勤=> id(PK),缺席日期(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 我创建了一个名为MyDates的表

CREATE TABLE MyDates (mydate date);

and this procedure to fill MyDates Table with Dates 和此过程用日期填充MyDates表

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'); 然后我调用了用日期CALL filldates('2017-01-01','2017-03-31')填充MyDates的过程;

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 这是 IMG 的屏幕截图

There are 3 issues with your query I can see. 我可以看到您的查询有3个问题。 The 1st 2 results in dropping the dates where no matching record is found, the 3rd potentially means that you get wrong counts: 1st 2会导致删除找不到匹配记录的日期,而3rd可能意味着您得到了错误的计数:

  1. 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. inner join employee on attendance.e_id_f = employee.e_id如果一天没有匹配的记录,则当天的attendance.e_id_f将为null。 The inner join will eliminate this record from the resultset. 内部联接将从结果集中消除该记录。 Solution: make this join a left as well. 解决方案:也使此连接成为左连接。

  2. 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. AND employee.dep_id = 4这只会将记录中包含与之相关的员工记录的记录保留在结果集中,因此如果您的缺勤日为0,则此条件会将其从结果集中删除。 Solution: include this criteria in the join condition. 解决方案:在连接条件中包括此条件。

  3. count(attendance.date_of_absence) - counts occurances from the attendance table, which will not be correct after adding the 2nd left join. count(attendance.date_of_absence) -计算出勤表中的出现次数,这在添加第二个左联接后将不正确。 Solution: use count(employee.dep_id) instead. 解决方案:改用count(employee.dep_id)

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. 另一种解决方案是使用嵌套联接,您在其中专门指示MySQL首先执行attendance inner join employee联接attendance inner join employee联接。 You still need to move the employee.dep_id = 4 condition to the join condition: 您仍然需要将employee.dep_id = 4条件移动到加入条件:

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. 在后一种情况下,嵌套的内部dep_id = 4可确保仅返回属于dep_id = 4那些出勤记录,然后将这些记录保留在您的日期表中。 In this case there is no need to change the field you are counting. 在这种情况下,无需更改您要计数的字段。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM