[英]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;
筆記:
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;
我發現子查詢版本更容易理解。
我的一般看法(由於我不在手機Atm上發帖,因此無需測試查詢):
您應該在查詢的第二個RIGHT JOIN
上使用RIGHT JOIN
。
您還將需要其他WHERE子句,即where employees.id is not null
不要忘記對計划表中的所有字段都使用ifull()
,即ifnull(schedule_link.id, schedule_link.id, schedule.myfield)
請注意,對於要顯示超出schedule
所有字段,都應該這樣做此查詢中的表
希望這些指南對您有幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.