Обновить

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

Если нужны все клиенты, а из заказов — только оплаченные, условие можно перенести в ON:

Если пишете "можно" - то показывайте и альтернативу. А заодно рассказывайте, в каком случае эти три варианта реализуют не две, а три разные логики.

Здравствуйте!
Спасибо, альтернативу действительно стоило показать. Для исходной задачи можно сначала отфильтровать заказы в подзапросе:

SELECT c.name, o.id AS order_id
FROM customers AS c
LEFT JOIN (    SELECT id, customer_id    FROM orders    WHERE status = 'paid'
) AS o ON o.customer_id = c.id;

В данном запросе это эквивалентно условию o.status = 'paid' в ON: сохранятся все клиенты, а присоединятся только оплаченные заказы.

Третья логика получается, например, если после обычного соединения по customer_id написать WHERE o.status = 'paid' OR o.id IS NULL. Здесь предполагаем, что orders.id — первичный ключ и не допускает NULL.

На данных из поста все три варианта дадут разные результаты:

  • Фильтр оплаты в ON: Анна с заказом №101, Борис и Вера с NULL вместо номера заказа.

  • Фильтр оплаты в WHERE: только Анна с заказом №101.

  • Фильтр в WHERE с добавлением OR o.id IS NULL: Анна с заказом №101 и Вера с NULL. Борис исчезнет.

У Бориса заказ нашёлся при соединении, поэтому строка с NULL для него не создаётся. Затем его неоплаченный заказ отбрасывает WHERE. У Веры заказов нет, поэтому созданная соединением строка с NULL проходит условие o.id IS NULL.

Получается, третий вариант сохраняет клиентов вообще без заказов, но исключает тех, у кого заказы есть и ни один не оплачен. Поэтому он не заменяет фильтрацию в ON для исходной задачи «сохранить всех клиентов». Стоило конкретно разобрать это в посте(

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации