Я понимаю разницу между WHERE
и HAVING
в SQL-запросе, но не понимаю, почему это отдельные предложения. Нельзя ли их объединить в одно предложение, которое могло бы обрабатывать как агрегированные, так и неагрегированные данные?
Почему WHERE и HAVING существуют в SQL как отдельные предложения?
Ответы (4)
Вот правило. Если условие относится к агрегатной функции, поместите это условие в предложение HAVING. В противном случае используйте предложение WHERE.
Вот еще одно правило: Вы не можете использовать HAVING, если вы не используете GROUP BY.
Основное отличие заключается в том, что WHERE нельзя использовать для сгруппированных элементов (например, SUM(число)), тогда как HAVING можно. Причина в том, что WHERE выполняется до группировки, а HAVING — после группировки. .
ДРУГОЕ РАЗЛИЧИЕ В предложении WHERE требуется, чтобы условие было столбцом в таблице, но в предложении HAVING можно использовать и столбец, и псевдоним.
Вот разница:
SELECT `value` v FROM `table` WHERE `v`>5;
Ошибка № 1054 – Неизвестный столбец "v" в разделе "где"
SELECT `value` v FROM `table` HAVING `v`>5; -- Get 5 rows
Предложение WHERE требует, чтобы условие было столбцом в таблице, но предложение HAVING может использовать как столбец, так и псевдоним.
Это связано с тем, что предложение WHERE фильтрует данные перед выбором, а предложение HAVING фильтрует данные после выбора.
Поэтому размещение условий в предложении WHERE будет более эффективным, если в таблице много строк.
Попробуйте EXPLAIN, чтобы увидеть ключевое отличие:
EXPLAIN SELECT `value` v FROM `table` WHERE `value`>5;
+----+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
| 1 | SIMPLE | table | range | value | value | 4 | NULL | 5 | Using where; Using index |
+----+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
EXPLAIN SELECT `value` v FROM `table` having `value`>5;
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
| 1 | SIMPLE | table | index | NULL | value | 4 | NULL | 10 | Using index |
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
Вы можете видеть, что WHERE или HAVING использует индекс, но строки разные.
Так что есть необходимость в них обоих, особенно когда нам нужна группировка и дополнительные фильтры.
GROUP BY
и даже SELECT
? В конце концов, можно использовать единый синтаксис, чтобы сказать, что извлекать, извлекать ли, как агрегировать и отображать ли все в одном. Конечно, это был бы не SQL.
- person ; 27.03.2014
Этот вопрос, кажется, иллюстрирует неправильное понимание того, что WHERE
и HAVING
отсутствуют до 1/2 информации, необходимой для полной обработки запроса.
Рассмотрим следующий SQL:
drop table if exists foo; create table foo (
ID int,
bar int
); insert into foo values (1, 1);
select now() as d, bar as b
from foo
where bar = 1 and d <= now()
having bar = 1 and ID = 1
;
В предложении where
элемент d
недоступен, поскольку элементы select
ed еще не были обработаны для его создания.
В пункте having
пункт ID
был исключен, поскольку он не был select
ed. В агрегированных запросах ID
может даже не иметь значения в контексте нескольких строк, объединенных в одну. ID
также может быть бессмысленным при join
объединении разных таблиц в один результат.
Можно ли это сделать? Конечно, но на бэкенде он будет работать так же, как и сейчас, потому что вам нужно что-то агрегировать, прежде чем вы сможете фильтровать на основе этой агрегации. В конечном счете, причина в том, что это логическое разделение различных процессов. Зачем тратить ресурсы на агрегирование записей, которые можно было бы отфильтровать с помощью WHERE
?
WHERE
— это предварительная обработка, которая выполняется в каждой строке. HAVING
— это постобработка, которая происходит после подсчета и консолидации результата. Два места, где что-то фильтруется, две оговорки. Мне кажется очень простым. Объединение их может показаться громоздким, поскольку их всегда нужно разбивать на части для обработки. Логика, как правило, заключается в том, чтобы разбивать сложные проблемы на простые части, а не объединять простые части в громоздкие конструкции.
- person ; 27.03.2014
GROUP BY
для получения точных результатов? Это можно было бы легко подразумевать и решить на бэкэнде.
- person Hart CO; 27.03.2014
На вопрос может полностью ответить только дизайнер, поскольку он задает намерение. Но подразумевается, что оба предложения делают одно и то же только для агрегированных и неагрегированных данных. Это не правда. "Предложение HAVING обычно используется вместе с предложением GROUP BY для фильтрации результатов совокупных значений. Однако HAVING можно указать без GROUP BY."
Насколько я понимаю, важно то, что «Предложение HAVING указывает дополнительные фильтры, которые применяются после фильтров предложения WHERE».
http://technet.microsoft.com/en-us/library/ms179270(v=sql.105).aspx
WHERE
, но и после того, как все остальное было рассчитано. (например, отдельные значения SELECT
и т. д.) HAVING
— это предложение, которое работает с окончательными строками результатов, тогда как WHERE
работает с тем, что извлекается. (предварительный фильтр на входе и постфильтр на выходе)
- person ; 27.03.2014
HAVING
условия, которое могло бы быть включено в пунктWHERE
. Единственными причинами было бы доказать, что это можно сделать, или, может быть, запутать людей. Невозможно получить разные результаты, потому что вы не можете ссылаться на неагрегированное поле вHAVING
, если оно не находится вGROUP BY
. - person Hart CO   schedule 27.03.2014