簡體   English   中英

如果在LEFT JOIN和WHERE子句中找不到結果,如何在MySQL查詢中返回NULL值

[英]How to return NULL values in MySQL query if no results in LEFT JOIN and WHERE clause are found

我的MySQL查詢有問題。

這是我的三個表:

雇員:

    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

和schedule_link:

    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

是否可以通過一個請求獲得此結果?

預先感謝您的幫助。

您需要將條件放在on子句中除第一個表之外的所有表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;

筆記:

  • 表別名使查詢更易於編寫和閱讀。
  • 反引號只會使查詢更難讀寫。
  • 不要將startend用作列名(即,如果可以的話,請重命名)。 它們是關鍵字(盡管不是保留關鍵字),因此它們在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;

我發現子查詢版本更容易理解。

我的一般看法(由於我不在手機Atm上發帖,因此無需測試查詢):

  1. 您應該在查詢的第二個RIGHT JOIN上使用RIGHT JOIN

  2. 您還將需要其他WHERE子句,即where employees.id is not null

  3. 不要忘記對計划表中的所有字段都使用ifull() ,即ifnull(schedule_link.id, schedule_link.id, schedule.myfield)請注意,對於要顯示超出schedule所有字段,都應該這樣做此查詢中的表

希望這些指南對您有幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM