выбранные элементы не должны появляться в предложении GROUP BY или использоваться в статистической функции - PullRequest
1 голос
/ 03 октября 2019

Меня учили и слышали, что в sql / mysql элементы в select предложении должны появляться в предложении GROUP BY или использоваться в статистической функции , как в здесь

Однако приведенный ниже пример мог изменить мое мнение.

Две таблицы: Студент (ключ - это sid)

sid  | name | email
========================
99901| mike | mike@a.edu
99902| jane | jane@b.edu
99903| peter| pete@b.edu

Взял (sid + oid вместе - это ключ, oid означает предложение идентификатора)

sid  | oid| grade
==================
99901| 1  | 100
99901| 2  | 30
99901| 3  | 40
99902| 4  | 100
99902| 5  | 100
99902| 6  | 40
99903| 6  | 95

Вопрос : я хочу найти sid, имя и среднюю оценку каждого ученикакоторый прошел как минимум 2 курса.

Ответ :

select s.sid, name, avg(grade) as average
from Student as s, Took as t
where s.sid = t.sid
group by s.sid
having count(*) >= 2;

Результат:

sid  | name | avgerage
=======================
99901| mike | 56.6667
99902| jane | 80.0000

На основе должно появиться в предложении GROUP BY или использоваться в статистической функции , запрос должен быть неверным, поскольку name отсутствует ни в групповом предложении, ни в статистической функции.

Я посмотрел некоторыесообщений и это , я понимаю, что хотя name не входит ни в групповое предложение, ни в агрегатную функцию, мы группируем по sid, чтоключ и каждый sid соответствуют только одному name, поэтому он не будет возвращать несколько опций, из которых sql не знает, какой из них вернуть. Чтобы подтвердить мое понимание, если я выберу еще один столбец email, все равно все в порядке;но если я выберу oid, это выдаст ошибку, потому что каждый sid соответствует более чем одному oid.

Может ли кто-нибудь исправить мое понимание, если оно неверно, или уточнить подробнее об этом утверждении: must appear in the GROUP BY clause or be used in an aggregate function

Спасибо.

Первое редактирование :

Кстати, я тестировал в MySQL 8.0.17

Второе редактирование :

Просто краткое изложение полезных ссылок, когда вы читаете ответы / комментарии ниже.

Функциональная зависимость

Изменение стандарта SQL

Ответы [ 2 ]

2 голосов
/ 03 октября 2019

Во-первых, вы должны использовать правильный, явный синтаксис JOIN:

select s.sid, s.name, avg(grade) as average
from Student s join
     Took t
     on s.sid = t.sid
group by s.sid
having count(*) >= 2;

Это будет работать из-за того, что называется функциональными зависимостями . По сути, это часть стандарта, которая гласит: Если вы group by первичный ключ или уникальный ключ, то вы можете включить любой из столбцов из этой таблицы.

Здесь - документация по теме.

То есть, поскольку база данных знает , что s.sid уникальна, можно использовать другие столбцы. Это часть стандарта. Единственная известная мне база данных, которая поддерживает это, - это Postgres.

1 голос
/ 03 октября 2019

Вас учили правильно.

Согласно стандарту SQL при использовании GROUP BY столбцы, которые могут появиться в предложении SELECT, делятся на три категории:

  1. Столбцы включены в предложение GROUP BY. В этом случае у вас есть s.sid.
  2. Агрегированные столбцы. В этом случае у вас есть avg(grade).
  3. Функционально зависимые столбцы случая # 1. Поскольку s.sid - это PK таблицы, вы можете включить s.name без его агрегирования.

Так что все хорошо.

Однако вы должны знать, что MySQL 5.7.4и старше позволяют включать другие столбцы в неагрегированную форму. Это ошибка / особенность MySQL, которую я лично нахожу подверженной ошибкам. Если вы сделаете это, MySQL тихо выберет одно значение случайным образом , не агрегируя его и не сообщая вам.

Эта функция может быть включена с помощью ONLY_FULL_GROUP_BYПараметр конфигурации (как @Shawn указал в комментариях) в более новых версиях MySQL, чтобы разрешить запуск старых / плохих запросов. Я бы постарался избежать его использования.

...