Почему условие левого соединения Mysql не соблюдается?

Запрос возвращает неожиданные результаты: почему?

Таблица заказов:

+----------------+
| Field          |
+----------------+
| orderNumber    |
| customerNumber |
+----------------+

Таблица деталей заказа:

+-----------------+
| Field           |
+-----------------+
| orderNumber     |
| productCode     |
+-----------------+

Рассмотрим следующий запрос:

SELECT 
    o.orderNumber, 
    o.customerNumber, 
    d.orderNumber,
    d.productCode
FROM
    orders o
LEFT JOIN orderdetails d 
    ON ((o.orderNumber = d.orderNumber) AND (o.orderNumber = 10123)) ;

Вот результат:

Я ожидаю увидеть строки, которые имеют orderNumber только 10123

Почему мы видим другие номера заказов? Я бы подумал, что условие соединения (т.е. o.orderNumber = 10123) должно было исключить эти другие строки? Для меня это действительно причудливо и волшебно, с неожиданными результатами: любые разъяснения о том, что происходит, будут очень признательны.

Обновление — добавление условия в предложение WHERE

Это правда, я мог бы добавить o.orderNumber = 10123 в предложение WHERE, что решило бы проблему, но меня беспокоит то, что при включении в предложение ON оно по-прежнему должно работать должным образом, не так ли? Почему? Поскольку условие вернет false, учитывая, что o.orderNumber НЕ 10123, и поэтому его следует исключить из набора результатов?

Обновление: воспроизводимый пример:

Вот база данных mysql: https://sp.mysqltutorial.org/wp-content/uploads/2018/03/mysqlsampledatabase.zip

Вот онлайн-версия, где вы можете вводить команды: https://www.mysqltutorial.org/tryit/

Спасибо!

есть несколько типов соединений... вам нужно понять их использование, прежде чем использовать их...

RoMEoMusTDiE 14.12.2020 00:43

Ваш синтаксис немного странный. Не включайте (o.orderNumber = 10123) в предложение ON. Переместите его в ГДЕ после соединения.

nomistic 14.12.2020 00:43

Я бы переместил o.orderNumber = 10123 из JOIN в WHERE, так как это не имеет отношения к столу, к которому вы присоединяетесь.

Phil 14.12.2020 00:43

Вы используете (o.orderNumber = 10123) в самом JOIN, а не как WHERE o.orderNumber = 10123.

Ergis 14.12.2020 00:44

Объясните, почему вы ожидаете того, чего ожидаете, или вы просто просите еще одну презентацию LEFT JOIN, и мы не знаем, где ваши недоразумения/неправильные представления. Обоснуйте то, что вы ожидаете, со ссылкой на авторитетную документацию или вы не исследовали и не объяснили должным образом. Это кодовый вопрос, поэтому, пожалуйста, приведите минимальный воспроизводимый пример. Это включает в себя предыдущий плюс-код и вывод в виде текста, который мы можем вырезать, вставить, запустить и отличить от вашего сообщения, а также того, что вы вырезали, вставили и запустили. PS LEFT JOIN ON возвращает строки INNER JOIN ON UNION ВСЕХ несопоставленных левых строк таблицы, расширенных значениями NULL. Знайте, какое ВНУТРЕННЕЕ СОЕДИНЕНИЕ.

philipxy 14.12.2020 02:25
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
5
72
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Если вы хотите отфильтровать набор результатов по заданному номеру заказа, вы должны указать это условие в предложении WHERE:

SELECT ...
FROM orders o
LEFT JOIN orderdetails d ON d.orderNumber = o.orderNumber
WHERE o.orderNumber = 10123;

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

...либо так, либо просто измените LEFT JOIN на INNER JOIN !

Ergis 14.12.2020 00:51

@Ergis: да, но это отфильтровывает заказы, в которых нет подробностей.

GMB 14.12.2020 00:52

Я уже знаю. Я просто сказал альтернатива, это его выбор!

Ergis 14.12.2020 00:57

@GMB спасибо за ваш ответ - меня смущает то, что условие в предложении «ON» должно по-прежнему исключать строки, которые не являются 10123, не так ли? Это связано с тем, что предложение вернет значение FALSE. Mysql затем пропустит эту строку? Мне интересно, почему мы должны фильтровать с помощью предложения WHERE, когда одно и то же условие можно отфильтровать с помощью предложения ON. разъяснения были бы очень признательны. хрс

BenKoshy 14.12.2020 01:04

@BKSpurgeon: он исключает строки, которых нет 10123 в левом соединении, а не во внешнем запросе. Для этого вам нужен пункт where. Или используйте inner join, и вам не нужно об этом беспокоиться.

GMB 14.12.2020 01:13

Короче говоря, вы запрашиваете все записи из таблицы orders. Ваше предложение соединения будет получать данные из orderdetails только тогда, когда у вас есть соответствие orderNumber и когда orderNumber равно 10123, но вы все равно получите все записи из orders.

Если вы хотите получить записи из orders только тогда, когда orderNumber равно 10123, вы должны использовать условие для этого в таблице orders. Обычный способ сделать это — использовать предложение WHERE.

При использовании LEFT JOIN вы получите совпадающие записи (на основе условия) из объединенной таблицы, но вы все равно получите все записи из ЛЕВОЙ таблицы.

Это должно работать.

SELECT 
    o.orderNumber, 
    o.customerNumber, 
    d.orderNumber,
    d.productCode
FROM
    orders o
LEFT JOIN orderdetails d 
    ON (o.orderNumber = d.orderNumber) 
WHERE o.orderNumber = 10123;

Это улучшение. (Но это все еще неясно. Например, что такое «выборка»? Вы используете его, когда некоторые входные данные отображаются как подстроки выходных строк. Никто не узнает об этом из «выборки». Остальное так же нечетко. Чтобы быть ясным и полным, нужно использовать достаточно слова, чтобы на самом деле сказать, что они означают, а не просто говорить неясные вещи, смутно соответствующие некоторым из них. См. Также версию на момент этого комментария другого ответа, который я прокомментировал. Не ясно. Неполный.)

philipxy 14.12.2020 07:06

«Предложение LEFT JOIN позволяет вам запрашивать данные из нескольких таблиц. Оно возвращает все строки из левой таблицы и соответствующие строки из правой таблицы. Если в правой таблице не найдено совпадающих строк, используется NULL». (https://www.sqlservertutorial.net/sql-server-basics/sql-server-left-join/). Таким образом, действительно нечего ожидать от условий «ON». Для LEFT JOIN они касаются только 2-й таблицы. Я бы порекомендовал автору лучше узнать виды JOIN

Это не ясное объяснение левого соединения. Например, вопреки кавычке ни одна из возвращаемых строк не является входной строкой. Например, возвращенные строки содержат входные строки как подстроки, но вы не говорите, какие именно и как именно. Также этот ответ не связывает то, что вы цитируете, с путаницей или ожиданиями спрашивающего. Кроме того, ваше письмо неясно и расплывчато. Также см. мой комментарий к вопросу.

philipxy 14.12.2020 03:20

Если вы хотите, чтобы JOIN отфильтровывал результаты, не соответствующие второй таблице, используйте внутреннее соединение:

SELECT o.orderNumber, o.customerNumber, d.orderNumber, d.productCode
FROM orders o JOIN
     orderdetails d 
     ON o.orderNumber = d.orderNumber 
WHERE o.orderNumber = 10123;

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

Фильтрация по orderNumber может быть либо в предложении ON, либо в предложении WHERE — они эквивалентны для внутреннего соединения. Однако я думаю, что более «традиционно» размещать такую ​​фильтрацию на одной таблице в предложении WHERE.

Другие вопросы по теме