Как вернуть значения NULL в запросе MySQL, если не найдено результатов в предложениях LEFT JOIN и WHERE - PullRequest
0 голосов
/ 13 мая 2018

У меня проблема с запросом 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

Можно ли получить этот результат с помощью одного запроса?

Заранее благодарю за помощь.

Ответы [ 2 ]

0 голосов
/ 13 мая 2018

Мой общий подход (без проверки запроса, так как я не отправляю сообщения с моего телефона):

  1. Вы должны использовать RIGHT JOIN при втором соединении в вашем запросе.

  2. Вам также понадобится дополнительное предложение WHERE, например where employees.id is not null

  3. Не забудьте использовать ifull() для всех полей таблицы расписания, т.е.ifnull(schedule_link.id, schedule_link.id, schedule.myfield) Обратите внимание, что это должно быть сделано для всех полей, которые вы хотите показать, которые выходят из таблицы schedule в этом запросе

Надеюсь, что эти рекомендации будут вам полезны.

0 голосов
/ 13 мая 2018

Необходимо указать условия для всех, кроме первой таблицы, в предложении 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;

Мне кажется, что подзапросной версией легче следовать.

...