如果在左join和where子句中找不到结果,如何在mysql查询中返回空值

cnjp1d6j  于 2021-06-21  发布在  Mysql
关注(0)|答案(2)|浏览(193)

我对mysql查询有问题。
这是我的三张table:
员工:

id  initials  deleted  
------  --------  ---------
     1  TV                0
     2  AH                0
     3  JE                0
     4  MA                0
     5  MJ                0
     6  CE                0
     7  KB                1
     8  KL                1

日程安排:

id  place                         start                  end  deleted  
------  --------------  -------------------  -------------------  ---------
     1  Somewhere       2018-05-11 16:48:17  2018-05-15 16:48:26          0
     2  Somewhere else  2018-05-12 16:48:50  2018-05-14 16:48:55          1
     3  Here            2018-05-13 00:00:00  2018-05-13 00:00:00          0
     4  Not here        2018-05-18 16:49:42  2018-05-16 16:49:48          0

和时间表链接:

id  id_employee  id_schedule  
------  -----------  -------------
     1            1              1
     2            1              2
     3            4              3
     4            5              4

我想要一个要求,返回所有有关的日期为每个员工的一天。即使员工没有找到任何记录,我也希望查询在其他列中返回其带有null的缩写。
以下是我当前的查询:

SELECT
  `employees`.`id`,
  `employees`.`initials`,
  `schedule`.`place`,
  `schedule`.`start`,
  `schedule`.`end`,
  `schedule`.`deleted`
FROM
  `employees`
  LEFT JOIN `schedule_link`
    ON (
      `employees`.`id` = `schedule_link`.`id_employee`
    )
  LEFT JOIN `schedule`
    ON (
      `schedule_link`.`id_schedule` = `schedule`.`id`
    )
WHERE (
    `employees`.`deleted` = '0'
    AND `schedule`.`deleted` = '0'
  )
  AND (
    DATE(CURDATE()) BETWEEN CAST(schedule.start AS DATE)
    AND CAST(schedule.end AS DATE)
  )

这将返回以下数据:

id  initials  place                    start                  end  deleted  
------  --------  ---------  -------------------  -------------------  ---------
     1  TV        Somewhere  2018-05-11 16:48:17  2018-05-15 16:48:26       0
     4  MA        Here       2018-05-13 00:00:00  2018-05-13 00:00:00       0

这是正确的,但我想要的是以下结果:

id  initials  place                    START                  END  deleted  
------  --------  ---------  -------------------  -------------------  ---------
     1  TV        Somewhere  2018-05-11 16:48:17  2018-05-15 16:48:26          0
     4  MA        Here       2018-05-13 00:00:00  2018-05-13 00:00:00          0
     2  AH        NULL       NULL                 NULL                         0
     3  JE        NULL       NULL                 NULL                         0   
     5  MJ        NULL       NULL                 NULL                         0        
     6  CE        NULL       NULL                 NULL                         0

一个请求就可以得到这个结果吗?
事先谢谢你的帮助。

fxnxkyjh

fxnxkyjh1#

我的一般看法(由于我不在电话atm机上发帖,所以没有测试查询):
你应该使用 RIGHT JOIN 第二次加入你的查询。
您还需要附加where子句,即。 where employees.id is not null 别忘了利用 ifull() 对于明细表中的所有字段,即。 ifnull(schedule_link.id, schedule_link.id, schedule.myfield) 请注意,这应该是为所有领域,你想显示出来的 schedule 此查询中的表
希望这些指南能对你有所帮助。

zzzyeukh

zzzyeukh2#

你需要把所有的条件,除了第一个表中 on 条款。你的 where 子句将外部联接转换为内部联接。
我还有一些建议:

SELECT e.id, e.initials, s.place, s.start, s.end, s.deleted
FROM employees e LEFT JOIN
     schedule_link sl
     ON e.id = sl.id_employee LEFT JOIN
     schedule s
     ON sl.id_schedule = s.id AND s.deleted = 0 AND
        CURDATE() BETWEEN CAST(s.start AS DATE) AND CAST(s.end AS DATE)
WHERE e.deleted = 0;

笔记:
表别名使查询更易于编写和读取。
反勾号只会使查询更难读写。
不要使用 start 以及 end 作为列名(即,如果可以,重命名它们)。它们是关键字(虽然不是保留的),因此它们在sql语句中还有其他用途。
我猜是的 deleted 是数字。不要使用单引号进行比较(除非列实际上是字符串)。 CURDATE() 已经是约会了。不需要转换。
我不建议使用 BETWEEN 与日期,因为一个挥之不去的时间部分的可能性。但是,您使用的是显式转换,因此代码明确地执行您想要的操作(可能会冒不使用可用索引的风险)。
编辑:
我懂了。因为日期条件在第三个表中,而不是在第二个表中,所以会得到重复的行。我想这会解决你的问题:

SELECT e.id, e.initials, ss.place, ss.start, ss.end, ss.deleted
FROM employees e LEFT JOIN
     (SELECT sl.id_employee, s.*
      FROM schedule_link sl JOIN
           schedule s
           ON sl.id_schedule = s.id AND s.deleted = 0
      WHERE CURDATE() BETWEEN CAST(s.start AS DATE) AND CAST(s.end AS DATE)
      ) ss
      ON e.id = ss.id_employee
WHERE e.deleted = 0;

这将包括每一个在时间框架上没有匹配项的员工。你还是会得到所有的唱片 schedule 如果有多个匹配项。
实际上,您可以在不使用子查询的情况下表达这一点:

SELECT e.id, e.initials, s.place, s.start, s.end, s.deleted
FROM employees e LEFT JOIN
     (schedule_link sl JOIN
      schedule s
      ON sl.id_schedule = s.id AND s.deleted = 0 AND
        CURDATE() BETWEEN CAST(s.start AS DATE) AND CAST(s.end AS DATE)
     )
     ON e.id = sl.id_employee
WHERE e.deleted = 0;

我发现子查询版本更容易理解。

相关问题