Синтаксис MySQL: больше значения, но НЕ IN (...) - PullRequest
0 голосов
/ 19 марта 2012

Таблица:

бронирования : id, идентификатор_пользователя, идентификатор_объекта, дата1, ...

booking_status : id, book_id, статус

статус - int, диапазон от 1 до 9 (запрос, подтверждено, оплачено, отменено пользователем и тому подобное), поэтому мне нужны все заказы, где статус не менее 4 (что означает платный), но не больше значения чем 4 (что означает отмену и т. д.).

До сих пор SELECT выглядит примерно так (я пропустил некоторые поля (...), чтобы сократить его):

SELECT b.date1, ..., u.name FROM bookings b
    LEFT JOIN user u ON (b.user_id = u.id)
    LEFT JOIN booking_status bs ON (b.id=bs.book_id)
  WHERE ((b.object_id=$object_id) AND (bs.status NOT IN (5,6,7,8,9)));"

... но он по-прежнему выбирает те бронирования, которые имеют статус бронирования больше 4. Есть идеи, как мне нужно изменить запрос ??

Заранее большое спасибо!


ОБНОВЛЕНИЕ: еще раз спасибо всем, я поражен тем, сколько прекрасных идей вы выдвинули! Есть действительно много способов сделать это, и я многому научился у вас, так что спасибо еще раз! Я попробую все ваши предложения и посмотрю на производительность, а пока я смешал ваши решения с этим запросом, , который работает на данный момент, но мне нужно проверить его дальше:

SELECT b.date, ..., u.name FROM bookings b
LEFT JOIN user u ON (b.user_id = u.id)
LEFT JOIN booking_status bs ON (b.id=bs.book_id AND bs.status<=4)
WHERE (b.object_id=$object_id) HAVING MAX(bs.status)=4

он не возвращает несколько строк, но возвращает строки с 4, исключает строки с более 4 и не имеет подзапросов ...

РЕДАКТИРОВАТЬ 2: Я снова отредактировал запрос ... с HAVING MAX (bs.status) = 4 он тогда работает ...

РЕДАКТИРОВАТЬ 3: извините, после тестирования различных случаев я должен признать, что я был слишком быстр, говоря, что это работает ...

Ответы [ 4 ]

3 голосов
/ 19 марта 2012

Если я правильно понимаю, то, что вам нужно, это:

SELECT b.date1, ..., u.name
  FROM bookings b
  LEFT JOIN user u ON b.user_id = u.id
 WHERE b.object_id = ...
   AND EXISTS
        ( SELECT 1
            FROM booking_status bs
           WHERE bs.book_id = b.id
             AND bs.status = 4
        )
   AND NOT EXISTS
        ( SELECT 1
            FROM booking_status bs
           WHERE bs.book_id = b.id
             AND bs.status > 4
        )
;

Проблема с вашим текущим запросом состоит в том, что он отфильтровывает все объединенные строки, где bs.status > 4, но не фильтруетиз объединенных строк, которые имеют такой же bookings.id, что и объединенная строка, где bs.status > 4.

1 голос
/ 20 марта 2012

Другой способ

SELECT id, 
       user_id, 
       object_id, 
       date1 
FROM   bookings b 
       INNER JOIN (SELECT book_id 
                   FROM   booking_status 
                   GROUP  BY book_id 
                   HAVING MAX(CASE 
                                WHEN status >= 4 THEN status 
                              END) = 4) bs 
         ON bs.book_id = b.id 

(или версия без подвыбора в ответ на комментарии)

SELECT b.id, 
       b.user_id, 
       b.object_id, 
       b.date1 
FROM   bookings b 
       INNER JOIN booking_status bs 
         ON bs.book_id = b.id 
GROUP  BY b.id /* Other RDBMSs would require all columns listed*/
HAVING MAX(CASE 
             WHEN bs.status >= 4 THEN bs.status 
           END) = 4 
1 голос
/ 19 марта 2012

Вот метод без подзапросов:

SELECT b.date1, ..., u.name
FROM bookings b
LEFT JOIN user u ON u.id = b.user_id
JOIN booking_status bs1
  ON bs1.book_id = b.id AND bs1.status = 4
LEFT JOIN booking_status bs2
  ON bs2.book_id = b.id AND bs2.status > 4
WHERE b.object_id = $object_id
  AND b2.book_id IS NULL

Этот запрос удаляет все строки, в которых есть статус для того же идентификатора, который больше 4.

1 голос
/ 19 марта 2012

на основе решения ruakh без соответствующих подзапросов:

select ...
from bookings b
join (select book_id from booking_status group by book_id having max(status) = 4
     ) bs on b.id = bs.book_id
left join user u on b.user_id = u.id
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...