Почему HAVING может ссылаться на COUNT (имя_столбца), но не на само имя_столбца? - PullRequest
0 голосов
/ 29 мая 2020

Я пытаюсь лучше понять, как работает MySQL. Я столкнулся с проблемой с подгруппами. Из вопроса Неизвестный столбец в 'имеющем предложении , я понимаю, почему этот код вернет ошибку:

SELECT b.Title, b.Isbn
FROM Book AS b
INNER JOIN Writing AS w ON w.Book_id = b.ID
GROUP BY b.ID
HAVING w.Author_id = 1 AND b.Title LIKE "%Head%"

Эта ошибка: «Неизвестный столбец' w.Author_id 'in' имеющий clause '"потому что:

Стандарт SQL требует, чтобы HAVING ссылался только на столбцы в предложении GROUP BY или столбцы, используемые в агрегатных функциях. Однако MySQL поддерживает расширение этого поведения и позволяет HAVING ссылаться на столбцы в списке SELECT и столбцы во внешних подзапросах.

Но если вместо w.Author_id = 1, я используйте COUNT(w.Author_id) > 1, код выполняется и работает правильно:

SELECT b.Title, b.Isbn
FROM Book AS b
INNER JOIN Writing AS w ON w.Book_id = b.ID
GROUP BY b.ID
HAVING COUNT(w.Author_id) > 1 AND b.Title LIKE "%Head%"

Итак, мой вопрос: что именно в COUNT() делает w.Author_id доступным? Прошу прощения, если это глупый / очевидный вопрос - я все еще новичок в SQL.

Ответы [ 2 ]

3 голосов
/ 29 мая 2020

Документация кажется довольно ясной по этому поводу. Но позвольте мне посмотреть, смогу ли я объяснить вам это лучше.

Предложение HAVING по сути является предложением WHERE, которое «имеет место» после GROUP BY. То есть агрегация уже произошла, поэтому доступны данные агрегированные данные.

В вашем примере агрегация не возвращает Author_Id. И MySQL не знает, как его сгенерировать.

Однако COUNT(w.Author_Id) - это агрегированный результат. MySQL может просто добавить это (концептуально) к результатам, возвращаемым агрегацией, и отфильтровать их.

Ваш запрос эквивалентен:

SELECT Title, Isbn
FROM (SELECT b.Title, b.Isbn, COUNT(*) as cnt
      FROM Book b JOIN
           Writing w
           ON w.Book_id = b.ID
      GROUP BY b.ID
     ) b
WHERE cnt > 1 AND b.Title LIKE '%Head%';

Тем не менее, запрос лучше записать как:

SELECT b.Title, b.Isbn
FROM Book b JOIN
     Writing w
     ON w.Book_id = b.ID
WHERE b.Title LIKE '%Head%'
GROUP BY b.ID
HAVING COUNT(*) > 1;

Вы можете фильтровать по title до агрегирования, что обычно намного эффективнее.

1 голос
/ 29 мая 2020

Когда вы помещаете w.Author_id в выражение COUNT(w.Author_id) > 1, вы удовлетворяете требованию для предложения HAVING, согласно которому

HAVING должен ссылаться только на столбцы в предложении GROUP BY или столбцы, используемые в агрегатных функциях

, в то время как столбец ID сам по себе не будет, потому что он не является частью предложения GROUP BY и не входит в агрегатную функцию (которая COUNT есть).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...