Необходимо указать условия для всех, кроме первой таблицы, в предложении 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
с датами из-за возможности длительного компонента времени. Однако вы используете явные преобразования, поэтому код однозначно делает то, что вы хотите (возможно, с риском не использовать доступный индекс).
EDIT:
Понятно. Поскольку условие даты находится в третьей таблице, а не во второй, вы получаете повторяющиеся строки. Я думаю, что это решит вашу проблему:
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;
Мне кажется, что подзапросной версией легче следовать.