WHERE используется для фильтрации записей до того, как на них воздействует GROUP BY (или в запросах, у которых нет группы)
HAVING используется для фильтрации строк после того, как на них воздействует GROUP BY. Вы можете указывать столбцы в предложении HAVING только в том случае, если они были сгруппированы или являются частью совокупности (означает, что они передаются какой-либо функции, такой как SUM (столбец), AVG (столбец), COUNT (столбец) и т. Д.)
Счета сотрудников, у которых было более одного повышения заработной платы:
--yes
SELECT emp_name
FROM pay_rise_log
WHERE dept = 'accounts'
GROUP BY emp_name
HAVING count(*) > 1
--yes - equivalent if HAVING wasn't a thing
SELECT emp_name
FROM (
--do this first, count the records
SELECT emp_name, COUNT(*) as ct
FROM pay_rise_log
WHERE dept = 'accounts'
GROUP BY emp_name
) a
WHERE a.ct > 1 --and now filter to more than one pay rise
--no, you can't use a count(*) (done during a group by) before the group by is performed
SELECT emp_name
FROM pay_rise_log
WHERE dept = 'accounts' AND count(*) > 1
GROUP BY emp_name
--no
SELECT emp_name
FROM pay_rise_log
WHERE dept = 'accounts'
GROUP BY emp_name
HAVING count(*) > 1 AND gender = 'male' --no, the gender column was not grouped and is not presented inside an aggregate function
--works, but is unusual. gender should be in the where clause
SELECT emp_name
FROM pay_rise_log
WHERE dept = 'accounts'
GROUP BY emp_name, gender
HAVING count(*) > 1 AND gender = 'male'
--works, but gender should be part of the WHERE clause to avoid needlessly counting females
--also has a potential bug if genders alphabetically after 'male' are present
--though it would count people who have been male even if they aren't currently, which may be a bonus?!
SELECT emp_name
FROM pay_rise_log
WHERE dept = 'accounts'
GROUP BY emp_name
HAVING count(*) > 1 AND MAX(gender) = 'male'
С точки зрения изучения MySQL немного затруднителен, потому что в некоторых конфигурациях вы можете опустить GROUP BY, и он сделает это для вас неявно, поэтому вы можете не осознавать, что выполняется GROUP BY
В ответ на ваш комментарий вы можете использовать WHERE перед группой по; Вы используете его, чтобы выбрать, какие записи вы хотите сгруппировать. Если в отделе счетов 100 000 сотрудников и только 100, то нет смысла группировать и подсчитывать ВСЕХ из них, а только отбрасывать 99% данных:
--yes
SELECT emp_name
FROM pay_rise_log
WHERE dept = 'accounts' --pick 100 employees
GROUP BY emp_name
HAVING count(*) > 1 --pick only those with 2 or more pay rises
--no (and potentially wrong too)
SELECT emp_name
FROM pay_rise_log --pick 100,000 employees
GROUP BY emp_name
HAVING count(*) > 1 and MAX(dept) = 'accounts' --pick only accounts staff who had more than 1 pay rise