Я использую NOT IN, а также IF в предложении Where подзапроса MySQL, это правильный путь? - PullRequest
0 голосов
/ 23 ноября 2018

Рабочий запрос: Мой запрос работает, и я также получаю желаемый результат.Я просто хочу знать, делаю ли я что-то не так, потому что слышал, что это не правильный способ использовать IF внутри Where, но в моем случае это даже в подзапросе.Я сделал этот запрос сам.Дайте мне знать, если есть лучшая альтернатива для моего запроса.

Ищу: Я пытаюсь найти всех тех сотрудников, которые не заняты между 14:00 и 15:00, где 14:00 и 15:00 - время, приходящее из полей ввода(как поиск).

 SELECT * 
   FROM `schedule` 
  WHERE appointment_id NOT IN (
          SELECT appointment_id 
            FROM `schedule` 
           WHERE ( IF(start_time < '14:00', '14:00', start_time) >= '14:00' 
             AND   IF(end_time > '15:00', '15:00', end_time) >= '14:00') 
             AND  (IF(start_time < '14:00', '14:00', start_time) <= '15:00' 
             AND   IF(end_time > '15:00', '15:00', end_time) <= '15:00') 
             AND  `appoint_date` = '2018-11-30')

Ответы [ 5 ]

0 голосов
/ 23 ноября 2018

Это подразумевается как дополнительный ответ на решение Тима

Разбивка вашего раздела ГДЕ (я снял лишние скобки)

WHERE IF(start_time < '14:00', '14:00', start_time) >= '14:00' /** Line 1 */
  AND IF(end_time > '15:00', '15:00', end_time) >= '14:00' /** Line 2 */
  AND IF(start_time < '14:00', '14:00', start_time) <= '15:00' /** Line 3 */
  AND IF(end_time > '15:00', '15:00', end_time) <= '15:00' /** Line 4 */
  AND `appoint_date` = '2018-11-30'

Взгляд на строку1, IF(start_time < '14:00', '14:00', start_time) всегда будет возвращать время, большее или равное '14:00' для ненулевого start_time .. таким образом, эта строка совпадает с WHERE start_time IS NOT NULL

Аналогично строка 4 может быть переписана AND end_time IS NOT NULL

Глядя на строку 2, довольно просто увидеть, что это эквивалентно AND start_time <= '15:00'.Любые манипуляции start_time с помощью IF влияют только на времена, которые приводят к истинному результату, и сохраняют их истинными

Точно так же строку 3 можно переписать AND end_time >= '14:00'

Соединяя все это вместе

WHERE start_time IS NOT NULL /** Line 1 */
  AND end_time >= '14:00' /** Line 2 */
  AND start_time <= '15:00' /** Line 3 */
  AND end_time IS NOT NULL /** Line 4 */
  AND `appoint_date` = '2018-11-30'

Теперь, когда любое сравнение с нулевым операндом возвращает false, строка 3 фактически дает вам строку 1 бесплатно

Аналогично, строка 2 фактически дает вам строку 4 бесплатно

Удалениеэти лишние строки, вы в конечном итоге с Тимом WHERE

WHERE end_time >= '14:00' 
  AND start_time <= '15:00'
  AND appoint_date = '2018-11-30'

Addendum

Еще одно преимущество рефакторинга ваши предложения IF в Тиме WHERE является то, что это позволяет двигателюиспользовать индекс start_time или end_time, чтобы удовлетворить эти условия.Это может дать значительный выигрыш в производительности

0 голосов
/ 23 ноября 2018

Если запрос дает желаемые результаты и достаточно быстр, то это нормально.Вы можете внести улучшения, например, создать индексы, если они не существуют (я считаю, appointment_id проиндексирован).Существует вероятность, что NOT EXISTS вместо NOT IN может быть улучшением.Я бы написал WHERE часть так:

WHERE (IF(start_time < '14:00', '14:00', start_time) BETWEEN '14:00' AND '15:00')
  AND (IF(end_time > '15:00', '15:00', end_time) BETWEEN '14:00' AND '15:00') 
  AND  (`appoint_date` = '2018-11-30')
0 голосов
/ 23 ноября 2018

То, что IF может быть полезным по умолчанию для фиксированного времени в SELECT.
Но в качестве критерия использование его для установки значения по умолчанию - просто накладные расходы.

Если вы также не хотитевключить те, которые начинаются до 14:00 и заканчиваются после 15:00?
Затем попробуйте это:

SELECT DISTINCT employee_id
FROM `schedule` s
WHERE `appoint_date` = '2018-11-30'
  AND NOT EXISTS (
        SELECT 1
        FROM `schedule` s2
        WHERE s2.`appoint_date` = '2018-11-30'
          AND s2.start_time < '15:00'
          AND s2.end_time > '14:00'
          AND s2.appointment_id = s.appointment_id
      );
0 голосов
/ 23 ноября 2018

Я предпочитаю not eixsts

 select * from schedule t where not exists
  (select 1 from schedule t1 where 
  t1.appointment_id=t.appointment_id and
  start_time>='14:00' and end_time<='15:00' and appoint_date` = '2018-11-30'
  from )
0 голосов
/ 23 ноября 2018

Я даже не вижу смысла IF вызовов, и мы можем переписать ваш запрос без них:

SELECT * 
FROM schedule 
WHERE appointment_id NOT IN (
    SELECT appointment_id 
    FROM schedule
    WHERE
        end_time     >= '14:00' AND -- this
        start_time   <= '15:00' AND -- and this tests for all possible cases of overlap
        appoint_date = '2018-11-30');

Мне удалось удалить два условия в вашем WHEREпункт, потому что они всегда будут правдой.Вот один из двух примеров:

IF (start_time < '14:00', '14:00', start_time) >= '14:00'

Это всегда будет верно, потому что любое время, которое 14:00 или более раннее, увеличивается до 14:00.Таким образом, такие времена всегда будут >= 14:00.Точно так же в любое время уже больше , чем 14:00 также будет проходить проверку.Таким образом, весь этот термин может быть удален, а также еще один термин.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...