Разница между HAVING и WHERE в SQL - PullRequest
0 голосов
/ 28 ноября 2018

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

В качестве конкретного примера, почему эти два запроса не дают одинаковый результат (вторые суммы quantity преждевременно, что подавляет вызов GROUP BY)?

Использование WHERE для получения количества кондо-продаж каждого агента по недвижимости.

SELECT agentId, SUM(quantity) total_sales 
  FROM sales s, houses h
  WHERE s.houseId = h.houseId AND h.type = "condo"
  GROUP BY agentId
  ORDER BY total_sales;

Попытка использования HAVING для получения того же количества, что и выше.

SELECT agentId, SUM(quantity) total_sales 
  FROM sales s, houses h
  GROUP BY agentId
  HAVING s.houseId = h.houseId AND h.type = "condo"
  ORDER BY total_sales;

Примечание: они были написаны / протестированы / выполнены в sqlite3.

Ответы [ 3 ]

0 голосов
/ 28 ноября 2018

WHERE фильтрует строки из базы данных.Затем, если запрос имеет агрегацию, агрегация запускается на основе функций агрегирования и предложения GROUP BY в запросе.После этой точки HAVING применяется для фильтрации результатов группировки.Единственная фильтрация, которую HAVING разрешает, это фильтрация по GROUP BY столбцам или вычисленным агрегатам.

Я должен предположить, что вы используете MySQL для вашего примера запроса, поскольку, как отмечали другие ответы, ваш HAVINGпредложение не имеет смысла, а в MySQL есть поведение по умолчанию, которое иногда проблематично и сбивает с толку.

0 голосов
/ 28 ноября 2018

Простой способ подумать об этом - рассмотреть порядок применения шагов.

Шаг 1: где предложение фильтрует данные

Шаг 2: Выполнено группирование по (SUM/ MAX / MIN / ETC)

Шаг 3: Наличие предложения фильтрует результаты

Итак, в ваших 2 примерах:

SELECT agentId, SUM(quantity) total_sales 
FROM sales s, houses h
WHERE s.houseId = h.houseId AND h.type = "condo"
GROUP BY agentId
ORDER BY total_sales;

Шаг 1: Фильтр по HouseId и Condo

Шаг 2: Суммируйте результаты (количество домов, соответствующих домовой и кондо)

SELECT agentId, SUM(quantity) total_sales 
FROM sales s, houses h
GROUP BY agentId
HAVING s.houseId = h.houseId AND h.type = "condo"
ORDER BY total_sales;

Шаг 1: Без фильтра

Шаг 2: Добавьте количествоиз всех домов

Шаг 3: Отфильтруйте результаты по houseid и condo.

Надеюсь, это прояснит происходящее.

Самый простой способ решить, какой из них использовать: - использовать WHERE для фильтрации данных - использовать HAVING для фильтрации результатов агрегации (SUM / MAX / MIN / ETC)

0 голосов
/ 28 ноября 2018

Во-первых, научитесь использовать правильный, явный, стандартный JOIN синтаксис.

Во-вторых, ваш запрос должен выглядеть следующим образом:

SELECT s.agentId, SUM(s.quantity) as total_sales 
FROM sales s JOIN
     houses h
     ON s.houseId = h.houseId
WHERE h.type = 'condo'
GROUP BY s.agentId
ORDER BY total_sales;

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

Дополнительные примечания:

  • Разделительдля строки есть одинарные кавычки.Если вы используете двойные кавычки, все может работать не так, как вы ожидаете.
  • Вы должны квалифицировать все ссылки на столбцы, особенно если ваш запрос ссылается на более чем одну таблицу.
  • JOIN условия принадлежатПредложение ON, а не предложение WHERE.
  • Фильтрация по h.type после агрегирование не имеет смысла.Если бы это работало, sum() включал бы не-кондо, потому что фильтрация происходит слишком поздно.
...