Запрос соединения MySQL только с одним из нескольких определенных значений

#mysql

#mysql

Вопрос:

У меня есть таблицы с отношением «один ко многим».

 rental
------
id
book_date

prices
------
rental_id
type_id
value
  

Обычный запрос соединения даст результаты

 select * from rental a join prices b on a.id = b.rental_id;
  

 id book_date  rental_id  type_id  value

1, 2016-10-04,  1,        8,       200
1, 2016-10-04,  1,       10,       300
2, 2016-10-04,  2,        8,       250
3, 2016-10-04,  3,        8,       200
3, 2016-10-04,  3,       10,       300
  

я хочу, чтобы, если запись цены имеет type_id = 10, то возьмите эту строку; если это не так, нужно взять строку с type_id = 8 . Результат, который я хочу:

 1    2016-10-04    1    10    300
2    2016-10-04    2     8    250
3    2016-10-04    3    10    300
  

У меня есть этот запрос, но, похоже, он не работает в моем случае:

 select * from rental a
join prices b 
on a.id = b.rental_id and 
      ( if(b.type_id = 10, b.type_id = 10, b.type_id = 8) )
ORDER BY a.id DESC LIMIT 20
  

Ответ №1:

я хочу, чтобы, если запись цены имеет type_id = 10, то она соединяется только с type_id 10, если нет, она соединяется с type_id = 8

Это означает, что запись с type_id 8 должна быть отброшена, если есть другая запись с type_id 10. Это «другое» вызывает другое СОЕДИНЕНИЕ, фактически ЛЕВОЕ СОЕДИНЕНИЕ, поскольку сравниваемая запись может не существовать:

 SELECT a.*, b.* FROM rental a
JOIN prices b ON (a.id = b.rental_id)
LEFT JOIN prices check ON (a.id = check.rental_id AND check.type_id = 10)

WHERE b.type_id = 10 OR (b.type_id = 8 AND check.type_id IS NULL)
  

Это означает, что СОЕДИНЕНИЕ получит все типы 8 и типа 10; тогда ЛЕВОЕ СОЕДИНЕНИЕ сделает так, чтобы тип 8 принимался, только если нет соответствующего типа 10:

        1 10 10
       2 8  10      # discarded
       2 10 10
       3 8  NULL
       4 15 NULL    # discarded
       4 8  NULL
  

Идентификатор 1 имеет только запись 10, оба запроса извлекают его, и он принимается. Идентификатор 2 имеет оба значения, поэтому запись 8-10 отбрасывается, потому что тип b равен 8, но тип c не равен NULL. Идентификатор 3 имеет только запись 8, поэтому 10-поисковое ЛЕВОЕ СОЕДИНЕНИЕ возвращает NULL, что соответствует второй части OR . Идентификатор 4 имеет идентификаторы типа_id 8 и 15, а 15 отбрасывается обеими частями OR.

Ответ №2:

если запись цены имеет type_id = 10, то она соединяется только с type_id 10, если нет, она соединяется с type_id = 8

Эта логика может быть применена путем выбора записи с максимальным type_id значением для каждого rental_id . Если это так, то вы можете просто добавить третье условие объединения, которое ограничит результирующий набор только записями, соответствующими этому дополнительному условию:

 SELECT a.*, b.*
FROM rental a
INNER JOIN prices b
    ON a.id = b.rental_id
INNER JOIN
(
    SELECT rental_id,
           CASE WHEN MAX(CASE WHEN type_id = 10 THEN 1 END) = 1 THEN 10
                WHEN MAX(CASE WHEN type_id = 8 THEN 1 END)  = 1 THEN 8
                ELSE MAX(type_id)
           END AS type_id
    FROM prices
    GROUP BY rental_id
) c
    ON b.rental_id = c.rental_id AND
       b.type_id   = c.type_id
  

Перейдите по ссылке ниже для запуска демо:

SQLFiddle

Комментарии:

1. Извините, забыл упомянуть, на самом деле 10 не является максимальным значением type_id, есть несколько больших чисел, чем 10. Поэтому я думаю, что я не могу использовать максимум для выбора. Если существует 10, используйте 10, если нет, используйте 8 вместо этого. спасибо 🙂