Какая разница между ИМ и ГДЕ?


261

Должно быть, я неправильно гуглю или у меня тупой момент времени.

Какая разница между HAVINGи WHEREв SQL SELECTутверждении?

РЕДАКТИРОВАТЬ: я пометил ответ Стивена как правильный, поскольку он содержал ключевой бит информации по ссылке:

Когда GROUP BYне используется, HAVINGведет себя как WHEREпредложение

Ситуация, в которой я видел ситуацию, не возникла WHERE, GROUP BYи именно здесь началось мое замешательство. Конечно, пока вы не знаете это, вы не можете указать это в вопросе.


44
Строка, которую вы цитируете, совсем не ключевая. Ключевой бит, как указал wcm , - это HAVINGфильтр постагрегации , тогда как фильтр предагрегированияWHERE .
Ник Чаммас

эта ссылка помогла мне понять ее лучше, чем все приведенные ниже комментарии, подумал, что кто-то может получить помощь по этому codeproject.com/Articles/25258/…
Lijin Durairaj

Ответы:



369

HAVING: используется для проверки условий после агрегации.
WHERE: используется для проверки условий перед агрегацией.

Этот код:

select City, CNT=Count(1)
From Address
Where State = 'MA'
Group By City

Дает вам таблицу всех городов в МА и количество адресов в каждом городе.

Этот код:

select City, CNT=Count(1)
From Address
Where State = 'MA'
Group By City
Having Count(1)>5

Дает вам таблицу городов в МА с более чем 5 адресами и количеством адресов в каждом городе.


7
Это должен быть принятый ответ. Различие между «иметь» и «где» делает это сразу ясно.
Пол

27

Разница в номер один для меня: если бы он HAVINGбыл удален из языка SQL, жизнь продолжалась бы более или менее так же, как и раньше. Конечно, запросы меньшинства должны были бы быть переписаны с использованием производной таблицы, CTE и т. Д., Но в результате их было бы легче понять и поддерживать. Может быть, код оптимизатора продавцов нужно будет переписать, чтобы учесть это, опять же возможность для улучшения в отрасли.

Теперь рассмотрим на минуту удаление WHEREиз языка. На этот раз большинство существующих запросов нужно было бы переписать без очевидной альтернативной конструкции. Кодировщики должны проявить творческий подход, например, внутреннее объединение с таблицей, которая, как известно, содержит ровно одну строку (например, DUALв Oracle), используя ONпредложение для имитации предыдущегоWHERE предложения. Такие конструкции будут изобретены; было бы очевидно, что в языке чего-то не хватает, и в результате ситуация будет еще хуже.

TL; DR, мы можем проиграть HAVINGзавтра, и все будет не хуже, возможно, лучше, но этого нельзя сказать WHERE.


Из ответов здесь, кажется, что многие люди не понимают, что HAVINGпункт может быть использован без GROUP BYпункта. В этом случае HAVINGпредложение применяется ко всему табличному выражению и требует, чтобы в предложении присутствовали только константы SELECT. Как правило, HAVINGпункт будет включать в себя агрегаты.

Это полезнее, чем кажется. Например, рассмотрим этот запрос, чтобы проверить, nameявляется ли столбец уникальным для всех значений в T:

SELECT 1 AS result
  FROM T
HAVING COUNT( DISTINCT name ) = COUNT( name );

Возможны только два результата: если HAVINGпредложение имеет значение true, то результатом будет одна строка, содержащая значение 1, в противном случае результатом будет пустой набор.


Будет ли это эквивалентно «ВЫБЕРИТЕ СЧЕТЧИК (ОТЛИЧНОЕ имя) = СЧЕТЧИК (имя) ОТ Т»?
MSpreij

@ MSpreij Не знаю, работает ли это для вас, но это не работает на SQL Server 2005, но первый работает
Джо,

22

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

Проверьте эту ссылку w3schools для получения дополнительной информации

Синтаксис:

SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name
HAVING aggregate_function(column_name) operator value

Запрос, такой как этот:

SELECT column_name, COUNT( column_name ) AS column_name_tally
  FROM table_name
 WHERE column_name < 3
 GROUP 
    BY column_name
HAVING COUNT( column_name ) >= 3;

... может быть переписан с использованием производной таблицы (и пропуская HAVING) следующим образом:

SELECT column_name, column_name_tally
  FROM (
        SELECT column_name, COUNT(column_name) AS column_name_tally
          FROM table_name
         WHERE column_name < 3
         GROUP 
            BY column_name
       ) pointless_range_variable_required_here
 WHERE column_name_tally >= 3;

3
Вы немного упустили момент: HAVINGбыл добавлен, потому что производные таблицы не были добавлены в язык, и до тех пор, пока они не стали SQL, они не были реляционно полными, и как только они неизбежно HAVINGстали избыточными.
сегодня,

21

Разница между ними заключается в отношении к предложению GROUP BY:

  • ГДЕ предшествует GROUP BY; SQL оценивает предложение WHERE перед группированием записей.

  • HAVING следует за GROUP BY; SQL оценивает HAVING после группировки записей.

выберите диаграмму утверждения

Ссылки


Поскольку GROUP BY и HAVING являются необязательными, на диаграмме показаны оба случая, просто следуйте стрелкам.
Пол Свитт

Пример запроса из моего ответа на этот вопрос: SELECT 1 AS result FROM T HAVING...- на вашей диаграмме я не могу обойтись HAVINGбез прохождения, GROUP BYно мой совершенно правильный и полезный запрос не имеет GROUP BY. Незначительный момент: у вас нет возможности включить литеральные значения в SELECTпредложение.
понедельник,

@onedaywhen Так как вы знаете о скрытой GROUP BY, почему вы не упомянули об этом? Вы знаете , ожидаете ли вы этого поведения или нет?
Пол Свитт

Мне кажется, вы цитируете меня вне контекста. Вопрос был об очевидном отклонении mySQL от Стандарта, все, кроме последнего параграфа моего ответа, описывают поведение Стандарта, а последний ссылается на «неявное предложение GROUP BY, упомянутое в других ответах ». Вы говорите, что ваша диаграмма предназначена для описания (всего) неявного поведения? Разве не было бы более полезно придерживаться только кода, который нужно написать, чтобы получить желаемое поведение?
четверг,

... Я не знаю, на какое поведение вы ссылаетесь во второй ссылке. Желаемый результат заключается в том, что вы исправляете диаграмму, чтобы показать правильный (явный) путь, который я упомянул. Подумайте об этом: диаграмма охватывает весь запрос, но вопрос интересует только WHERE->HAVINGчасть, поэтому я думаю, что заслуживает пристального внимания к деталям. Если вы считаете, что мой ответ неправильный, отредактируйте его или опубликуйте предложенное исправление в комментариях.
четверг,

12

HAVINGиспользуется, когда вы используете агрегат, такой как GROUP BY.

SELECT edc_country, COUNT(*)
FROM Ed_Centers
GROUP BY edc_country
HAVING COUNT(*) > 1
ORDER BY edc_country;

8

ГДЕ применяется как ограничение на множество, возвращаемое SQL; он использует встроенные в SQL операции и индексы и поэтому является самым быстрым способом фильтрации наборов результатов. Всегда используйте ГДЕ, когда это возможно.

ЕСТЬ необходима для некоторых совокупных фильтров. Он фильтрует запрос ПОСЛЕ того, как sql извлек, собрал и отсортировал результаты. Следовательно, он намного медленнее, чем WHERE, и его следует избегать, за исключением тех ситуаций, которые требуют этого.

SQL Server позволит вам обойтись без использования HAVING, даже если ГДЕ будет намного быстрее. Не делай этого.


Поддержка производных таблиц в языке SQL означает, что ваше утверждение «HAVING необходимо для некоторых фильтров совокупности» неверно.
сегодня,

1
Неплохо подмечено. За три года, прошедшие с того момента, как я написал этот ответ, я определенно перешел на использование производных таблиц, в которых раньше я использовал HAVING. Я не продумал вопрос о том, имеет ли HAVING еще какие-то варианты использования, которые имеют смысл. Я также не знаю, будет ли производная таблица универсально работать лучше, чем HAVING.
davidcl

7

Предложение WHERE не работает для агрегатных функций
означает: вы не должны использовать, как этот бонус: имя таблицы

SELECT name  
FROM bonus  
GROUP BY name  
WHERE sum(salary) > 200  

ЗДЕСЬ Вместо использования предложения WHERE вы должны использовать HAVING ..

без использования предложения GROUP BY предложение HAVING просто работает как предложение WHERE

SELECT name  
FROM bonus  
GROUP BY name  
HAVING sum(salary) > 200  

4

Разница ч / б WHEREи HAVINGоговорка:

Основное различие между предложением WHEREи HAVINGвыражением заключается в том, что WHEREон используется для операций со строками и HAVINGдля операций со столбцами.

Зачем нам нужна HAVINGоговорка?

Как мы знаем, агрегатные функции могут выполняться только над столбцами, поэтому мы не можем использовать агрегатные функции в WHEREпредложении. Поэтому мы используем агрегатные функции в HAVINGпредложении.


2

Когда GROUP BYне используются, WHEREи HAVINGположение, по существу , эквивалентны.

Однако когда GROUP BYиспользуется:

  • Предложение WHEREиспользуется для фильтрации записей из результата. Фильтрация происходит до создания каких-либо группировок.
  • Предложение HAVINGиспользуется для фильтрации значений из группы (т. Е. Для проверки условий после агрегирования в группы).

Ресурс отсюда


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

2

Один способ думать об этом состоит в том, что предложение has является дополнительным фильтром к предложению where.

Предложение WHERE используется для фильтрации записей из результата. Фильтр срабатывает до создания каких-либо группировок. Предложение HAVING используется для фильтрации значений из группы


1

В агрегированном запросе (любой запрос, в котором используется агрегатная функция) предикаты в предложении where оцениваются перед созданием агрегированного промежуточного набора результатов,

Предикаты в условии Имеются применяются к совокупному результирующему набору ПОСЛЕ его создания. Вот почему условия предикатов для агрегатных значений должны быть помещены в предложение «В наличии», а не в предложение «Где», и поэтому вы можете использовать псевдонимы, определенные в предложении «Выбор» в предложении «Наличие», но не в предложении «Где».


1

У меня была проблема, и я обнаружил другую разницу между WHEREи HAVING. Он не действует одинаково на индексированные столбцы.

WHERE my_indexed_row = 123 покажет строки и автоматически выполнит «ORDER ASC» для других проиндексированных строк.

HAVING my_indexed_row = 123 показывает все от самой старой «вставленной» строки до самой новой, без упорядочивания.


Откуда вы знаете, что это определенная разница между двумя, а не случайностью реализации конкретного SQL-сервера, который вы использовали?
JdeBP

Я только что проверил это на MariaDB. Я думаю, что это был SQL-сервер, который я использовал 8 лет назад, который дал разные результаты.
Симмониз

0

От сюда .

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

в отличие от предложения WHERE, которое применяется к строкам базы данных


Источник говорит: «Использование позиций столбцов устарело, поскольку синтаксис был удален из стандарта SQL». К сожалению, это неправильно: ничто никогда не удаляется из Стандарта, и по иронии судьбы именно поэтому у нас все еще есть HAVINGдесятилетия после того, как он «устарел» производными таблицами.
onedaywhen

Немного педантичный, но цитата неверна, например, рассмотреть SELECT 1 FROM T HAVING COUNT(*) >= 1;- не ссылаются на столбцы в GROUP BYпредложении (их нет) и столбцы в агрегатных функциях (запрос не ссылается на столбцы вообще).
понедельник,

0

Во время работы над проектом это был и мой вопрос. Как указано выше, HAVING проверяет условие для результата запроса, который уже найден. Но ГДЕ предназначен для проверки условия во время выполнения запроса.

Позвольте мне привести пример, чтобы проиллюстрировать это. Предположим, у вас есть таблица базы данных, как эта.

usertable {int userid, date datefield, int dailyincome}

Предположим, в таблице есть следующие строки:

1, 2011-05-20, 100

1, 2011-05-21, 50

1, 2011-05-30, 10

2, 2011-05-30, 10

2, 2011-05-20, 20

Теперь мы хотим получить useridS и sum(dailyincome)чейsum(dailyincome)>100

Если мы напишем:

ВЫБЕРИТЕ идентификатор пользователя, сумма (dailyincome) ОТ пользователя, ГДЕ сумма (dailyincome)> 100 GROUP BY идентификатор пользователя

Это будет ошибкой. Правильный запрос будет:

ВЫБЕРИТЕ идентификатор пользователя, сумма (dailyincome) ОТ ГРУППЫ, доступной пользователю BYID ИМЕЮ С суммой (dailyincome)> 100


0

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


0

Когда GROUP BY не используется, предложения WHERE и HAVING по существу эквивалентны.

Однако, когда используется GROUP BY:

  • Предложение WHERE используется для фильтрации записей из результата. Фильтрация происходит до создания каких-либо группировок.
  • Предложение HAVING используется для фильтрации значений из группы (т. Е. Для проверки условий после выполнения агрегирования в группы).

-1

Я использую HAVING для ограничения запроса на основе результатов статистической функции. Например, выберите * в группе бла-бла, ЧТО-ТО, ЧТО (ЧТО-ТО)> 0


-1

Может быть просто, что предмет «где» - это строка, тогда как предмет «наличия» - это группа. Я прав?


3
Вы должны быть уверены, прежде чем опубликовать ответ. Это может вводить в заблуждение других.
pippin1289
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.