#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 Рад помочь, удачи вам.