Для чего нужен right join
Операции LEFT JOIN, RIGHT JOIN
Объединяют записи исходных таблиц при использовании в любом предложении FROM.
Синтаксис
FROM таблица1 [ LEFT | RIGHT ] JOIN таблица2
ON таблица1.поле1 оператор_сравнения таблица2.поле2
Операции LEFT JOIN и RIGHT JOIN состоят из следующих элементов:
Имена таблиц, содержащих объединяемые записи.
Имена полей, которые соединены. Поля должны быть одного типа тип данных и содержать данные одинакового типа, но имена этих полей могут быть одинаковыми.
Замечания
Операция LEFT JOIN создает левое внешнее соединение. С помощью левого внешнего соединения выбираются все записи первой (левой) таблицы, даже если они не соответствуют записям во второй (правой) таблице.
Операция RIGHT JOIN создает правое внешнее соединение. С помощью правого внешнего соединения выбираются все записи второй (правой) таблицы, даже если они не соответствуют записям в первой (левой) таблице.
Например, в случае с таблицами «Отделы» (левая) и «Сотрудники» (правая) можно воспользоваться операцией LEFT JOIN для выбора всех отделов (включая те, в которых нет сотрудников). Чтобы выбрать всех сотрудников (в том числе и не закрепленных за каким-либо отделом), используйте RIGHT JOIN.
В следующем примере показано, как можно объединить таблицы Categories и Products по полю CategoryID. Результат запроса представляет собой список категорий, включая те, которые не содержат товаров.
SELECT CategoryName, ProductName FROM Categories LEFT JOIN Products ON Categories.CategoryID = Products.CategoryID;
Чтобы создать запрос, результатом которого являются только те записи, для которых совпадают данные в связующих полях, воспользуйтесь операцией INNER JOIN.
Операции LEFT JOIN и RIGHT JOIN могут быть вложены в операцию INNER JOIN, но операция INNER JOIN не может быть вложена в операцию LEFT JOIN или RIGHT JOIN. Подробные сведения о вложении объединений можно найти в статье, посвященной операции INNER JOIN.
Вы можете связать несколько предложений ON. Сведения о связывании предложений см. в статье, посвященной операции INNER JOIN.
При попытке связи полей, содержащих данные типа Memo или объекты OLE, возникнет ошибка.
Оператор языка SQL JOIN предназначен для соединения двух или более таблиц базы данных по совпадающему условию. Этот оператор существует только в реляционных базах данных. Именно благодаря JOIN реляционные базы данных обладают такой мощной функциональностью, которая позволяет вести не только хранение данных, но и их, хотя бы простейший, анализ с помощью запросов. Разберём основные нюансы написания SQL-запросов с оператором JOIN, которые являются общими для всех СУБД (систем управления базами данных). Для соединения двух таблиц оператор SQL JOIN имеет следующий синтаксис:
После одного или нескольких звеньев с оператором JOIN может следовать необязательная секция WHERE или HAVING, в которой, также, как в простом SELECT-запросе, задаётся условие выборки. Общим для всех СУБД является то, что в этой конструкции вместо JOIN может быть указано INNER JOIN, LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL OUTER JOIN, CROSS JOIN (или, как вариант, запятая).
INNER JOIN (внутреннее соединение)
Запрос с оператором INNER JOIN предназначен для соединения таблиц и вывода результирующей таблицы, в которой данные полностью пересекаются по условию, указанному после ON.
Если вы хотите выполнить запросы к базе данных из этого урока на MS SQL Server, но эта СУБД не установлена на вашем компьютере, то ее можно установить, пользуясь инструкцией по этой ссылке .
Таблицы этой базы данных с заполненными данными имеют следующий вид.
Catnumb | Cat_name | Price |
10 | Стройматериалы | 105,00 |
505 | Недвижимость | 210,00 |
205 | Транспорт | 160,00 |
30 | Мебель | 77,00 |
45 | Техника | 65,00 |
Part_ID | Part | Cat |
1 | Квартиры | 505 |
2 | Автомашины | 205 |
3 | Доски | 10 |
4 | Шкафы | 30 |
5 | Книги | 160 |
Результатом выполнения запроса будет следующая таблица:
Part | Cat | Price |
Квартиры | 505 | 210,00 |
Автомашины | 205 | 160,00 |
Доски | 10 | 105,00 |
Шкафы | 30 | 77,00 |
В результирующей таблице нет Книг, так как эта запись ссылается на категорию, которой нет в таблице Categories, и Техники, так как эта запись имеет внешний ключ в таблице Categories, на который нет ссылки в таблице Parts.
В ряде случаев при соединениях таблиц составить менее громоздкие запросы можно с помощью предиката EXISTS и без использования JOIN.
Написать запросы SQL с JOIN самостоятельно, а затем посмотреть решения
Пример 2. Определить самого востребованного актёра за последние 5 лет.
Оператор JOIN использовать 2 раза. Использовать COUNT(), CURDATE(), LIMIT 1.
Пример 3. Вывести список актеров, которые в одном спектакле играют более одной роли, и количество их ролей.
Оператор JOIN использовать 1 раз. Использовать HAVING, GROUP BY.
Подсказка. Оператор HAVING применяется к числу ролей, подсчитанных агрегатной функцией COUNT.
LEFT OUTER JOIN (левое внешнее соединение)
Запрос с оператором LEFT OUTER JOIN предназначен для соединения таблиц и вывода результирующей таблицы, в которой данные полностью пересекаются по условию, указанному после ON, и дополняются записями из первой по порядку (левой) таблицы, даже если они не соответствуют условию. У записей левой таблицы, которые не соответствуют условию, значение столбца из правой таблицы будет NULL (неопределённым).
Для получения результирующей таблицы, в которой данные из двух таблиц полностью пересекаются по условию и дополняются всеми данными из таблицы Parts, которые не соответствуют условию, пишем следующий запрос:
Результатом выполнения запроса будет следующая таблица:
Part | Cat | Price |
Квартиры | 505 | 210,00 |
Автомашины | 205 | 160,00 |
Доски | 10 | 105,00 |
Шкафы | 30 | 77,00 |
Книги | 160 | NULL |
RIGHT OUTER JOIN (правое внешнее соединение)
Запрос с оператором RIGHT OUTER JOIN предназначен для соединения таблиц и вывода результирующей таблицы, в которой данные полностью пересекаются по условию, указанному после ON, и дополняются записями из второй по порядку (правой) таблицы, даже если они не соответствуют условию. У записей правой таблицы, которые не соответствуют условию, значение столбца из левой таблицы будет NULL (неопределённым).
Для получения результирующей таблицы, в которой данные из двух таблиц полностью пересекаются по условию и дополняются всеми данными из таблицы Categories, которые не соответствуют условию, пишем следующий запрос:
Результатом выполнения запроса будет следующая таблица:
Part | Cat | Price |
Квартиры | 505 | 210,00 |
Автомашины | 205 | 160,00 |
Доски | 10 | 105,00 |
Шкафы | 30 | 77,00 |
NULL | 45 | 65,00 |
FULL OUTER JOIN (полное внешнее соединение)
Запрос с оператором FULL OUTER JOIN предназначен для соединения таблиц и вывода результирующей таблицы, в которой данные полностью пересекаются по условию, указанному после ON, и дополняются записями из первой (левой) и второй (правой) таблиц, даже если они не соответствуют условию. У записей, которые не соответствуют условию, значение столбцов из другой таблицы будет NULL (неопределённым).
Для получения результирующей таблицы, в которой данные из двух таблиц полностью пересекаются по условию и дополняются всеми данными как из таблицы Parts, так и из таблицы Categories, которые не соответствуют условию, пишем следующий запрос:
Результатом выполнения запроса будет следующая таблица:
Part | Cat | Price |
Квартиры | 505 | 210,00 |
Автомашины | 205 | 160,00 |
Доски | 10 | 105,00 |
Шкафы | 30 | 77,00 |
Книги | 160 | NULL |
NULL | 45 | 65,00 |
Псевдонимы соединяемых таблиц
Пример 7. Переписать запрос из примера 1 с использованием псевдонимов соединяемых таблиц.
Запрос будет следующим:
Запрос вернёт то же самое, что и запрос в примере 1, но он гораздо компактнее.
JOIN и соединение более двух таблиц
A_Id | Part_ID | Date_start | Date_end | Text |
21 | 1 | ‘2018-02-11’ | ‘2018-04-20’ | «Продаю. « |
22 | 1 | ‘2018-02-11’ | ‘2018-05-12’ | «Продаю. « |
. | . | . | . | . |
27 | 1 | ‘2018-02-11’ | ‘2018-04-02’ | «Продаю. « |
28 | 2 | ‘2018-02-11’ | ‘2018-04-21’ | «Продаю. « |
29 | 2 | ‘2018-02-11’ | ‘2018-04-02’ | «Продаю. « |
30 | 3 | ‘2018-02-11’ | ‘2018-04-22’ | «Продаю. « |
31 | 4 | ‘2018-02-11’ | ‘2018-05-02’ | «Продаю. « |
32 | 4 | ‘2018-02-11’ | ‘2018-04-13’ | «Продаю. « |
33 | 3 | ‘2018-02-11’ | ‘2018-04-12’ | «Продаю. « |
34 | 4 | ‘2018-02-11’ | ‘2018-04-23’ | «Продаю. « |
Запрос будет следующим:
Cat_name |
Недвижимость |
Транспорт |
CROSS JOIN (перекрестное соединение)
Запрос будет следующим:
Запрос вернёт таблицу из 5 * 5 = 25 строк, фрагмент которой приведён ниже:
Catnumb | Cat_name | Price | Part_ID | Part | Cat |
10 | Стройматериалы | 105,00 | 1 | Квартиры | 505 |
10 | Стройматериалы | 105,00 | 2 | Автомашины | 205 |
10 | Стройматериалы | 105,00 | 3 | Доски | 10 |
10 | Стройматериалы | 105,00 | 4 | Шкафы | 30 |
10 | Стройматериалы | 105,00 | 5 | Книги | 160 |
. | . | . | . | . | . |
45 | Техника | 65,00 | 1 | Квартиры | 505 |
45 | Техника | 65,00 | 2 | Автомашины | 205 |
45 | Техника | 65,00 | 3 | Доски | 10 |
45 | Техника | 65,00 | 4 | Шкафы | 30 |
45 | Техника | 65,00 | 5 | Книги | 160 |
Как видно из примера, если результат такого запроса и имеет какую-либо ценность, то это, возможно, наглядная ценность в некоторых случаях, когда не требуется вывести структурированную информацию, тем более, даже самую простейшую аналитическую выборку. Кстати, можно указать выводимые столбцы из каждой таблицы, но и тогда информационная ценность такого запроса не повысится.
Но для CROSS JOIN можно задать условие соединения! Результат будет совсем иным. При использовании оператора «запятая» вместо явного указания CROSS JOIN условие соединения задаётся не словом ON, а словом WHERE.
Запрос будет следующим:
Запрос вернёт то же самое, что и запрос в примере 1:
Part | Cat | Price |
Квартиры | 505 | 210,00 |
Автомашины | 205 | 160,00 |
Доски | 10 | 105,00 |
Шкафы | 30 | 77,00 |
MySQL и JOINы
Поводом для написания данной статьи послужили некоторые дебаты в одной из групп linkedin, связанной с MySQL, а также общение с коллегами и хабролюдьми 🙂
В данной статье хотел написать что такое вообще JOINы в MySQL и как можно оптимизировать запросы с ними.
Что такое JOINы в MySQL
В MySQL термин JOIN используется гораздо шире, чем можно было бы предположить. Здесь JOINом может называться не только запрос объединяющий результаты из нескольких таблиц, но и запрос к одной таблице, например, SELECT по одной таблице — это тоже джоин.
Все потому, что алгоритм выполнения джоинов в MySQL реализован с использованием вложенных циклов. Т.е. каждый последующий JOIN это дополнительный вложенный цикл. Чтобы выполнить запрос и вернуть все записи удовлетворяющие условию MySQL выполняет цикл и пробегает по записям первой таблицы параллельно проверяя соответствия условиям описанных в теле запроса, когда находятся записи, удовлетворяющие условиям — во вложенном цикле по второй таблице ищутся записи соответствующие первым и удовлетворяющие условиям проверки и т.д.
Прмер обычного запроса с INNER JOIN
где Р — условия склейки таблиц и фильтры в WHERE условии.
Можно представить такой псевдокод выполнения такого запроса.
где конструкция t1||t2||t3 означает конкатенацию столбцов из разных таблиц.
Если в запросе встречаются OUTER JOINs, например, LEFT OUTER JOIN
то алгоритм выполнения этого запроса MySQL будет выглядеть как-то так
Итак, как мы видим, JOINы это просто группа вложенных циклов. Так почему же в MySQL и UNION и SELECT и запросы с SUBQUERY тоже джоины?
MySQL оптимизатор старается приводить запросы к тому виду к которому ему удобней обрабатывать и выполнять запросы по стандартной схеме.
С SELECT все понятно — просто цикл без вложенных циклов. Все UNION выполняются как отдельные запросы и результаты складываются во временную таблицу, и потом MySQL работает уже с этой таблицей, т.е. проходясь циклом по записям в ней. С Subquery та же история.
Приводя все к одному шаблону, например, МySQL переписывает все RIGHT JOIN запросы на LEFT JOIN эквиваленты.
Но стратегия выполнения запросов через вложенные циклы накладывает некоторые ограничения, например, в связи с такой схемой MySQL не поддерживает выполнение FULL OUTER JOIN запросов.
Но результат такого запроса можно получить с помощью UNION двух запросов на LEFT JOIN и на RIGHT JOIN
Пример самого запроса можно посмотреть по ссылке на вики.
План выполнения JOIN запросов
В отличии от других СУРБД MySQL не генерирует байткод для выполнения запроса, вместо этого MySQL генерирует список инструкций в древовидной форме, которых придерживается engine выполнения запроса выполняя запрос.
Это дерево имеет следующий вид и имеет название «left-deep tree»
В отличии от сбалансированных деревьев (Bushy plan), которые применяются в других СУБД (например Oracle)
JOIN оптимизация
Теперь перейдем к самому интересному — к оптимизации джоинов.
MySQL оптимизатор, а именно та его часть, которая отвечает за оптимизацию JOIN-ов выбирает порядок в котором будет производиться склейка имеющихся таблиц, т.к. можно получить один и тот же результат (датасет) при различном порядке таблиц в склейке. MySQL оптимизатор оценивает стоимость различных планов и выбирает с наименьшей стоимостью. Единицей оценки является операция единичного чтения страницы данных размером в 4 килобайта из произвольного места на диске.
Для выбранного плана можно узнать стоимость путем выполнения команды
SHOW SESSION STATUS LIKE ‘Last_query_cost’;
после выполнения интересующего нас запроса. Переменная Last_query_cost является сессионной переменной. Описание переменной Last_query_cost в MySQL документации можно найти здесь — dev.mysql.com/doc/refman/5.1/en/server-status-variables.html#option_mysqld_Last_query_cost
Оценка основана на статистике: количество страниц памяти, занимаемое таблицей и/или индексами для этой таблицы, cardinality (число уникальных значений) индексов, длинна записей и индексов, их распределение и т.д. Во время своей оценки оптимизатор не рассчитывает на то, что какие-то части попадут в кеш, оптимизатор предполагает, что каждая операция чтения это обращение к диску.
Иногда анализатор-оптимизатор не может проанализировать все возможные планы выполнения и выбирает неправильный. Например, если у нас INNER JOIN по 3м таблицам, то возможных вариантов у анализатора — 3! = 6, а если у нас склейка по 10 таблицам, то тут возможных вариантов уже 10! = 3628800… MySQL не может проанализировать столько вариантов, поэтому в таком случае он использует алгоритм «жадного» поиска.
И вот как раз для решения данной проблемы, нам может пригодиться конструкция STRAIGHT_JOIN. На самом деле я противник подобных хаков как FORCE INDEX и STRAIGH_JOIN, точней против их бездумного использования везде где только можно и нельзя. В данном случае — можно 🙂 Выяснив (либо экспериментальным путем делая запросы с STRAIGH_JOIN и оценивая Last_query_cost, либо эмпирическим путем) нужный порядок джоинов можно переписать запрос с таблицами в соответствующем порядке и добавить STRAIGH_JOIN к данному запросу, таким образом мы сразу убьем двух зайцев — определим правильный план выполнения запроса (это главный заяц) и сэкономим время на стадии «Statistic» (Все стадии выполнения запроса можно посмотреть установив профайлинг запросов командой SET PROFILING =1, я описывал это в своей предыдущей статье по теме профайлинга запросов в MySQL )
Но не стоит применять этот хак ко всем запросам, расчитывая произвести оптимизацию на спичках и сэкономить время на составление плана выполнения запроса оптимизатором и добавлять STRAIGH_JOIN ко всем запросам с джоинами, т.к. данные меняются и склейка, которая оптимальна сейчас может перестать быть оптимальной со временем, и тогда запросы начнуть очень сильно лагать.
Также, как уже говорилось выше, результаты джоинов помещаются во временные таблицы, поэтому зачастую уместно применять «derived table» в котором мы накладываем все необходимые нам условия на выборку, а также указываем LIMIT и порядок сортировки. В данном случае мы избавимся от избыточности данных во временной таблице, а также проведем сортировку на раннем этапе (по результату одной выборки, а не финальной склейки, что уменьшит размеры записей которые будут сортироваться).
Стандартный пример подхода описанного выше. Простая выборка для отношения много к многим: новости и теги к ним.
Ну и на последок небольшая задачка, которую я иногда задаю на собеседованиях 🙂
Есть новостной блоггерный сайт. Есть такие сущности как новости и комментарии к ним.
Задача — нужно написать запрос, который выводит список из 10 новостей определенного типа (задается пользователем) отсортированные по времени издания в хронологическом порядке, а также к каждой из этих новостей показать не более 10 последних коментариев, т.е. если коментариев больше — показываем только последние 10.
Все нужно сделать одним запросом. Да, это, может, и не самый лучший способ, и вы вольны предложить другое решение 🙂
Oracle PL/SQL •MySQL •MariaDB •SQL Server •SQLite
Базы данных
SQL оператор JOINS
В этом учебном материале вы узнаете, как использовать SQL JOINS с синтаксисом и примерами.
Описание
SQL JOINS используются для извлечения данных из нескольких таблиц. SQL JOIN выполняется всякий раз, когда две или более таблицы перечислены в операторе SQL.
Существует 4 различных типа соединений SQL:
Итак, давайте обсудим синтаксис SQL JOIN, рассмотрим наглядные иллюстрации SQL JOINS и рассмотрим несколько примеров.
SQL INNER JOIN (простое соединение)
Скорее всего, вы уже писали SQL запрос, который использует SQL INNER JOIN. Это наиболее распространенный тип соединения SQL. INNER JOIN возвращает все строки из нескольких таблиц, где выполняется условие соединения.
Синтаксис
Синтаксис INNER JOIN в SQL:
Рисунок.
Пример
Давайте рассмотрим пример использования INNER JOIN в запросе.
В этом примере у нас есть таблица customer и следующими данными:
customer_id | first_name | last_name | favorite_website |
---|---|---|---|
4000 | Justin | Bieber | google.com |
5000 | Selena | Gomez | bing.com |
6000 | Mila | Kunis | yahoo.com |
7000 | Tom | Cruise | oracle.com |
8000 | Johnny | Depp | NULL |
9000 | Russell | Crowe | google.com |
И таблица orders со следующими данными:
order_id | customer_id | order_date |
---|---|---|
1 | 7000 | 2019/06/18 |
2 | 5000 | 2019/06/18 |
3 | 8000 | 2019/06/19 |
4 | 4000 | 2019/06/20 |
5 | NULL | 2019/07/01 |
Выполним следующий SQL оператор:
Будет выбрано 4 записи. Вот результаты, которые вы должны получить:
customer_id | order_id | order_date |
---|---|---|
4000 | 4 | 2019/06/20 |
5000 | 2 | 2019/06/18 |
7000 | 1 | 2019/06/18 |
8000 | 3 | 2019/06/19 |
SQL LEFT OUTER JOIN
Другой тип соединения называется LEFT OUTER JOIN. Этот тип соединения возвращает все строки из таблиц с левосторонним соединением, указанным в условии ON, и только те строки из другой таблицы, где объединяемые поля равны (выполняется условие соединения).
Синтаксис
Синтаксис для LEFT OUTER JOIN в SQL:
В некоторых базах данных ключевое слово OUTER опущено и записывается просто как LEFT JOIN.
Рисунок
Пример
Теперь давайте рассмотрим пример, который показывает, как использовать LEFT OUTER JOIN в операторе SELECT.
customer_id | first_name | last_name | favorite_website |
---|---|---|---|
4000 | Justin | Bieber | google.com |
5000 | Selena | Gomez | bing.com |
6000 | Mila | Kunis | yahoo.com |
7000 | Tom | Cruise | oracle.com |
8000 | Johnny | Depp | NULL |
9000 | Russell | Crowe | google.com |
И таблицу orders со следующими данными:
order_id | customer_id | order_date |
---|---|---|
1 | 7000 | 2019/06/18 |
2 | 5000 | 2019/06/18 |
3 | 8000 | 2019/06/19 |
4 | 4000 | 2019/06/20 |
5 | NULL | 2019/07/01 |
Введите следующий SQL оператор:
Будет выбрано 6 записей. Вот результаты, которые вы получите:
customer_id | order_id | order_date |
---|---|---|
4000 | 4 | 2019/06/20 |
5000 | 2 | 2019/06/18 |
6000 | NULL | NULL |
7000 | 1 | 2019/06/18 |
8000 | 3 | 2019/06/19 |
9000 | NULL | NULL |
SQL RIGHT OUTER JOIN JOIN
Другой тип соединения называется SQL RIGHT OUTER JOIN. Этот тип соединения возвращает все строки из таблиц с правосторонним соединением, указанным в условии ON, и только те строки из другой таблицы, где объединяемые поля равны (выполняется условие соединения).
Синтаксис
Синтаксис для RIGHT OUTER JOIN в SQL:
В некоторых базах данных ключевое слово OUTER опущено и записывается просто как RIGHT JOIN.
Рисунок
На этом рисунке SQL RIGHT OUTER JOIN возвращает затененную область:
Пример
Теперь давайте рассмотрим пример, который показывает, как использовать RIGHT OUTER JOIN в операторе SELECT.
customer_id | first_name | last_name | favorite_website |
---|---|---|---|
4000 | Justin | Bieber | google.com |
5000 | Selena | Gomez | bing.com |
6000 | Mila | Kunis | yahoo.com |
7000 | Tom | Cruise | oracle.com |
8000 | Johnny | Depp | NULL |
9000 | Russell | Crowe | google.com |
И таблицу orders со следующими данными:
order_id | customer_id | order_date |
---|---|---|
1 | 7000 | 2019/06/18 |
2 | 5000 | 2019/06/18 |
3 | 8000 | 2019/06/19 |
4 | 4000 | 2019/06/20 |
5 | NULL | 2019/07/01 |
Введите следующий SQL оператор:
Будет выбрано 5 записей. Вот результаты, которые вы должны получить:
customer_id | order_id | order_date |
---|---|---|
NULL | 5 | 2019/07/01 |
4000 | 4 | 2019/06/20 |
5000 | 2 | 2019/06/18 |
7000 | 1 | 2019/06/18 |
8000 | 3 | 2019/06/19 |
SQL FULL OUTER JOIN
Другой тип объединения называется SQL FULL OUTER JOIN. Этот тип объединения возвращает все строки из LEFT таблицы и RIGHT таблицы со значениями NULL в месте, где условие соединения не выполняется.
Синтаксис
Синтаксис для SQL FULL OUTER JOIN:
В некоторых базах данных ключевое слово OUTER опускается и записывается просто как FULL JOIN.
Рисунок
Пример
Давайте рассмотрим пример, который показывает, как использовать FULL OUTER JOIN в операторе SELECT.
customer_id | first_name | last_name | favorite_website |
---|---|---|---|
4000 | Justin | Bieber | google.com |
5000 | Selena | Gomez | bing.com |
6000 | Mila | Kunis | yahoo.com |
7000 | Tom | Cruise | oracle.com |
8000 | Johnny | Depp | NULL |
9000 | Russell | Crowe | google.com |
И таблицу orders со следующими данными:
order_id | customer_id | order_date |
---|---|---|
1 | 7000 | 2019/06/18 |
2 | 5000 | 2019/06/18 |
3 | 8000 | 2019/06/19 |
4 | 4000 | 2019/06/20 |
5 | NULL | 2019/07/01 |
Введите следующий SQL оператор:
SELECT customers.customer_id,
orders.order_id,
orders.order_date
FROM customers
FULL OUTER JOIN orders
ON customers.customer_id = orders.customer_id
ORDER BY customers.customer_id;
Будет выбрано 7 записей. Вот результаты, которые вы получите:
customer_id | order_id | order_date |
---|---|---|
NULL | 5 | 2019/07/01 |
4000 | 4 | 2019/06/20 |
5000 | 2 | 2019/06/18 |
6000 | NULL | NULL |
7000 | 1 | 2019/06/18 |
8000 | 3 | 2019/06/19 |
9000 | NULL | NULL |
Как видите, строки, где customer_id равен 6000 и 9000, будут включены, но поля order_id и order_date для этих записей содержат значение NULL. Строка, где order_id равен 5, также будет включена, но поле customer_id для этой записи имеет значение NULL.