Почему WHERE и HAVING существуют в SQL как отдельные предложения?

Я понимаю разницу между WHERE и HAVING в SQL-запросе, но не понимаю, почему это отдельные предложения. Нельзя ли их объединить в одно предложение, которое могло бы обрабатывать как агрегированные, так и неагрегированные данные?


person Nathan St. John    schedule 27.03.2014    source источник
comment
Вот правило. Если условие относится к агрегатной функции, поместите это условие в предложение HAVING. В противном случае используйте предложение WHERE. Вот еще одно правило: вы не можете использовать HAVING, если вы не используете GROUP BY.   -  person prem30488    schedule 27.03.2014
comment
Я знаю, что условия, ссылающиеся на агрегацию, должны быть записаны в предложении HAVING, но я не понимаю, почему для этого понадобилось отдельное предложение. Что будет потеряно, если создать, скажем, предложение FILTER ON, которое будет вести себя как WHERE для неагрегированных условий и как HAVING в противном случае. Есть ли что-то, что было бы потеряно при объединении этих двух предложений?   -  person Nathan St. John    schedule 27.03.2014
comment
Основное отличие состоит в том, что WHERE нельзя использовать для сгруппированного элемента (например, SUM(число)), тогда как HAVING можно. Причина в том, что WHERE выполняется до группировки, а HAVING выполняется после группировки. ДРУГОЕ РАЗЛИЧИЕ В предложении WHERE требуется, чтобы условие было столбцом в таблице, но предложение HAVING может использовать как столбец, так и псевдоним. Таким образом, они оба необходимы.   -  person prem30488    schedule 27.03.2014
comment
Была ли когда-нибудь причина, по которой вы могли бы поместить в предложение HAVING условие, которое можно было бы поместить в предложение WHERE?   -  person Nathan St. John    schedule 27.03.2014
comment
Имейте в виду, что SQL, как и COBOL, изначально предназначался для того, чтобы его могли использовать менеджеры, исключая программистов. Если бы это имело смысл, то у менеджеров не было бы никакой надежды понять это.   -  person Hot Licks    schedule 27.03.2014
comment
@NathanSt.John Я не могу придумать причин для включения в пункт HAVING условия, которое могло бы быть включено в пункт WHERE. Единственными причинами было бы доказать, что это можно сделать, или, может быть, запутать людей. Невозможно получить разные результаты, потому что вы не можете ссылаться на неагрегированное поле в HAVING, если оно не находится в GROUP BY.   -  person Hart CO    schedule 27.03.2014


Ответы (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 использует индекс, но строки разные.

Так что есть необходимость в них обоих, особенно когда нам нужна группировка и дополнительные фильтры.

person prem30488    schedule 27.03.2014
comment
Я понимаю разницу между двумя пунктами. Просто кажется, что их можно легко записать как одно предложение фильтрации. На самом деле первое правило, которое вы дали, говорит, как это сделать: возьмите ваш список условий и поместите те из них, у которых есть агрегатные функции, в предложении HAVING, остальные — в WHERE. Зачем нужно вручную разделять условия? - person Nathan St. John; 27.03.2014
comment
но для указания условия поиска для группы или агрегатной функции предложение WHERE не будет работать ... так что же должно быть альтернативой? Предложение HAVING работает, поскольку предложение WHERE не работает - person prem30488; 27.03.2014
comment
Предложение HAVING похоже на предложение WHERE, но применяется только к группам в целом, тогда как предложение WHERE применяется к отдельным строкам. Запрос может содержать как предложение WHERE, так и предложение HAVING. Предложение WHERE сначала применяется к отдельным строкам в таблицах. Группируются только те строки, которые соответствуют условиям в предложении WHERE. Затем предложение HAVING применяется к строкам результирующего набора. В результатах запроса отображаются только те группы, которые соответствуют условиям HAVING. Вы можете применять предложение HAVING только к столбцам, которые также появляются в предложении GROUP BY или в агрегатной функции. - person prem30488; 27.03.2014
comment
@NathanSt.John Итак, вместо одного простого синтаксиса для оценки того, должна ли одна строка появляться в двух разных местах, у нас будет один более сложный синтаксис для оценки всего сразу. Почему бы не избавиться от GROUP BY и даже SELECT? В конце концов, можно использовать единый синтаксис, чтобы сказать, что извлекать, извлекать ли, как агрегировать и отображать ли все в одном. Конечно, это был бы не SQL. - person ; 27.03.2014
comment
Я предполагаю, что это показалось мне странным, потому что у нас нет выбора в этом вопросе (какие условия входят в предложения WHERE и какие условия входят в HAVING, полностью определены). Поскольку на самом деле выбора нет, я удивился, почему нам вообще дали выбор. Зачем открывать возможность совершить ошибку? Я согласен, что есть аналогичная проблема с GROUP BY. На основании других частей запроса полностью определяется, что там должно появиться. Зачем заставлять нас это писать? Теперь я понимаю, что это делается для того, чтобы все было ясно, а не потому, что это необходимо. - person Nathan St. John; 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 недоступен, поскольку элементы selected еще не были обработаны для его создания.

В пункте having пункт ID был исключен, поскольку он не был selected. В агрегированных запросах ID может даже не иметь значения в контексте нескольких строк, объединенных в одну. ID также может быть бессмысленным при joinобъединении разных таблиц в один результат.

person Community    schedule 27.03.2014

Можно ли это сделать? Конечно, но на бэкенде он будет работать так же, как и сейчас, потому что вам нужно что-то агрегировать, прежде чем вы сможете фильтровать на основе этой агрегации. В конечном счете, причина в том, что это логическое разделение различных процессов. Зачем тратить ресурсы на агрегирование записей, которые можно было бы отфильтровать с помощью WHERE?

person Hart CO    schedule 27.03.2014
comment
Если бы это был тот же самый процесс на бэкенде, зачем делать два пункта, когда один мог бы сделать всю работу? Я согласен, что объединение записей, которые вы могли бы отфильтровать, является пустой тратой ресурсов, так почему бы просто не всегда сначала применять неагрегированные условия? Почему мы должны писать эти условия в отдельном пункте? - person Nathan St. John; 27.03.2014
comment
Согласовано. WHERE — это предварительная обработка, которая выполняется в каждой строке. HAVING — это постобработка, которая происходит после подсчета и консолидации результата. Два места, где что-то фильтруется, две оговорки. Мне кажется очень простым. Объединение их может показаться громоздким, поскольку их всегда нужно разбивать на части для обработки. Логика, как правило, заключается в том, чтобы разбивать сложные проблемы на простые части, а не объединять простые части в громоздкие конструкции. - person ; 27.03.2014
comment
@ NathanSt.John Это логическое различие, которое требует различия. Я чувствую, что этого достаточно, есть сотни подобных вопросов, например: Почему все неагрегированные поля должны быть перечислены в GROUP BY для получения точных результатов? Это можно было бы легко подразумевать и решить на бэкэнде. - person Hart CO; 27.03.2014
comment
Я предполагаю, что различие было сделано для того, чтобы сделать логику явной, но я хотел убедиться, что не было и более глубокой причины. Спасибо за разъяснения. - person Nathan St. John; 27.03.2014

На вопрос может полностью ответить только дизайнер, поскольку он задает намерение. Но подразумевается, что оба предложения делают одно и то же только для агрегированных и неагрегированных данных. Это не правда. "Предложение HAVING обычно используется вместе с предложением GROUP BY для фильтрации результатов совокупных значений. Однако HAVING можно указать без GROUP BY."

Насколько я понимаю, важно то, что «Предложение HAVING указывает дополнительные фильтры, которые применяются после фильтров предложения WHERE».

http://technet.microsoft.com/en-us/library/ms179270(v=sql.105).aspx

person CuriousLayman    schedule 27.03.2014
comment
Не только после WHERE, но и после того, как все остальное было рассчитано. (например, отдельные значения SELECT и т. д.) HAVING — это предложение, которое работает с окончательными строками результатов, тогда как WHERE работает с тем, что извлекается. (предварительный фильтр на входе и постфильтр на выходе) - person ; 27.03.2014