MySQL Внутренняя группа объединения по учебному вопросу

#mysql

#MySQL

Вопрос:

https://www.mysqltutorial.org/tryit/query/mysql-inner-join/#2 Привет, ребята! Интересно, почему после того, как я удаляю GROUP BY orderNumber then, он извлекает только одну строку:

введите описание изображения здесь

Это их ошибка в базе данных «учебника» или это правильное поведение MySQL? Если это правильно, то почему он дает именно этот результат?

Ответ №1:

SQL «агрегатные функции», в том числе SUM(), COUNT(), MIN(), MAX() среди прочих, требуют фрейма для агрегирования. Обычно это один или несколько других столбцов для применения того SUM() или иного агрегата, и GROUP BY именно так вы указываете этот фрейм.

Совокупный запрос без каких-либо GROUP BY намеков на то, что вы берете SUM() все строки, соответствующие фильтру WHERE предложений запроса.

MySQL отличается от большинства других СУБД тем, что позволяет вам удалять GROUP BY с неагрегированными столбцами SELECT и все равно получать некоторый набор строк из вашего запроса. В Oracle, MS SQL Server или Postgresql запрос без GROUP BY будет синтаксической ошибкой. Они также будут рассматривать это как ошибку, если вы использовали GROUP BY orderNumber , все еще включая status в SELECT список. A GROUP BY должен включать каждый столбец, который находится в SELECT списке, который не используется в совокупности SUM(), COUNT(), MIN(), MAX() и т. Д.

Но MySQL снисходительно относится к его присутствию и вместо этого пытается угадать, к какому фрейму применить ваш SUM() агрегат. Иногда он может получить ответ, который вы на самом деле ожидали, но в большинстве случаев значения, которые он дает вам для неагрегированных столбцов, по существу неопределенны. Это сведет несколько возможных значений к одному, и у вас не будет возможности выбрать, какое из них вы получите.

Это результат запроса, который вы видите. MySQL выбрал orderNumber = 10100 и status = 'Shipped' пойти с вашим SUM() , даже если они конкретно не связаны с этой суммой. Сумма в вашем результате 9604190.61 — это сумма quantityOrdered * priceEach для ВСЕХ строк в этой таблице, несмотря на то, что orderNumber говорится.

Документация по GROUP BY обработке MySQL

Таким образом, самая надежная версия вашего запроса и единственная версия, которая будет работать за пределами MySQL, где вы действительно можете предсказать результаты, будет:

 SELECT 
    T1.orderNumber,
    status,
    SUM(quantityOrdered * priceEach) total
FROM
    orders AS T1
        INNER JOIN
    orderdetails AS T2 ON T1.orderNumber = T2.orderNumber
GROUP BY 
  orderNumber,
  status /* added */
;
 

Обратите внимание, что учебник опущен status из GROUP BY , хотя он есть SELECT . Это было бы ошибкой в большинстве других СУБД.

Обработка MySQL по умолчанию этой ошибки изменилась в последних версиях. До версии 5.7 этот ONLY_FULL_GROUP_BY режим был отключен по умолчанию, что, возможно, привело к тому, что многие разработчики стали зависимыми от поведения группировки. В последних версиях ONLY_FULL_GROUP_BY включен по умолчанию и предотвращает запросы с отсутствующим или неполным GROUP BY .

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

1. Просто чтобы заметить, что ссылка ссылается на документацию 5.7, которая верна в отношении приведенного выше аргумента, но этот аргумент слегка игнорирует текущую версию.

2. @Strawberry Спасибо — ссылка указывает на 8 и добавлена информация о современных значениях по умолчанию

3. Вау. Большое вам спасибо, Майкл! Вы приложили огромные усилия, чтобы ответить на мой вопрос, теперь я начинаю видеть вещи яснее, спасибо!

4. @SergejFomin Рад помочь, удачи вам.