Левое и правое объединение в запросе

0

Друг попросил меня о помощи в построении запроса, который показал бы, сколько кусков каждой модели было продано в каждый день месяца, показывая нули, когда никакие куски не продавались по определенной модели в определенный день, даже если нет товары любой модели продаются в этот день. Я придумал запрос ниже, но он работает не так, как ожидалось. Я только получаю записи для проданных моделей, и я не знаю почему.

select days_of_months.`Date`,
       m.NAME as "Model",
       count(t.ID) as "Count"
  from MODEL m
  left join APPLIANCE_UNIT a on (m.ID = a.MODEL_FK and a.NUMBER_OF_UNITS > 0)
  left join NEW_TICKET t on (a.NEW_TICKET_FK = t.ID and t.TYPE = 'SALES'
and t.SALES_ORDER_FK is not null)
 right join (select date(concat(2009,'-',temp_months.id,'-',temp_days.id)) as "Date"
               from temp_months
              inner join temp_days on temp_days.id <= temp_months.last_day
              where temp_months.id = 3 -- March
             ) days_of_months on date(t.CREATION_DATE_TIME) =
date(days_of_months.`Date`)
 group by days_of_months.`Date`,
       m.ID, m.NAME

Я создал временные таблицы temp_months и temp_days, чтобы получить все дни в течение любого месяца. Я использую MySQL 5.1, но я пытаюсь сделать запрос ANSI-совместимым.

Теги:
join

3 ответа

6
Лучший ответ

Вы должны CROSS JOIN указать свои даты и модели, чтобы у вас была ровно одна запись для каждой пары дневной модели независимо от того, а затем LEFT JOIN другие таблицы:

SELECT  date, name, COUNT(t.id)
FROM    (
        SELECT ...
        ) AS days_of_months
CROSS JOIN
        model m
LEFT JOIN
        APPLIANCE_UNIT a
ON      a.MODEL_FK = m.id
        AND a.NUMBER_OF_UNITS > 0
LEFT JOIN
        NEW_TICKET t
ON      t.id = a.NEW_TICKET_FK
        AND t.TYPE = 'SALES'
        AND t.SALES_ORDER_FK IS NOT NULL
        AND t.CREATION_DATE_TIME >= days_of_months.`Date`
        AND t.CREATION_DATE_TIME < days_of_months.`Date` + INTERVAL 1 DAY
GROUP BY
        date, name

Как вы это делаете, теперь вы получаете NULL в model_id за те дни, когда у вас нет продаж, и они сгруппированы вместе.

Обратите внимание на условие JOIN:

AND t.CREATION_DATE_TIME >= days_of_months.`Date`
AND t.CREATION_DATE_TIME < days_of_months.`Date` + INTERVAL 1 DAY

вместо

DATE(t.CREATION_DATE_TIME) = DATE(days_of_months.`Date`)

Это поможет сделать ваш запрос sargable (оптимизирован по индексам)

  • 0
    Вам не нужно делать специальные соединения. Я не слишком знаком с MySQL, но на сервере SQL, если вы пропустите внутренний / внешний, по умолчанию это внутренний.
  • 1
    @dan s: ВЛЕВО и ВПРАВО подразумевают НАРУЖНОЕ.
Показать ещё 1 комментарий
0

Вы ищете OUTER присоединиться. Левое внешнее соединение создает результирующий набор с записью с левой стороны соединения, даже если на правой стороне нет записи, к которой нужно подключиться. Правое внешнее соединение делает то же самое в противоположном направлении, создает запись для правой боковой таблицы, даже если левая сторона не имеет соответствующей записи. Любой столбец, проецируемый из таблицы, у которой нет записи, будет иметь значение NULL в результате соединения.

0

Вам нужно использовать внешние соединения, так как они не требуют, чтобы каждая запись в двух соединенных таблицах имела соответствующую запись.

http://dev.mysql.com/doc/refman/5.1/en/join.html

  • 0
    Если вы прочитаете запрос, вы заметите, что я уже использую левое и правое внешние соединения.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню