Чем отличаются WHERE и HAVING?
Это один из самых популярных вопросов на стажера, джуна и иногда мидла de/da. Я думаю, практически все знают что нужно отвечать.
Вот, например, в тг канале @data_analysis_it был дан такой ответ https://t.me/data_analysis_it/83 :
Все четко и понятно.
Deepseek даст такой краткий ответ:
Примерно тоже самое.
Это база, ее обязательно надо знать. В целом такого ответа на собеседовании будет достаточно.
НО! Но я вам хочу рассказать о важном нюансе, о котором очень много инженеров не знает:
HAVING можно использовать без GROUP BY!
Пример:
select max(campaign_id) from public.costs
having max(campaign_id)>2
--Результат 100.
select count(campaign_id) from public.costs
having count(campaign_id)>1000
--Результат 39300
В примере HAVING применяется не к группам, а ко всей таблице в целом, в данном случае группой является вся выборка. То есть в select-e выполняется просто функция, допустим count(*) , ко всем данным, но и еще можно сразу добавить фильтр по этому значению.
Вроде ничего важного, вряд ли кто-то таким образом будет использовать having без group by, просто прикольная фишка.
На самом деле данная фишка используется.
На моей прошлой работе, в одном красном банке, в архитектуре ETL была настроена система Eventwait-ов (флагов) таким образом:
Допустим у нас есть слой витрин данных, расчет таблиц в этом слое за сегодня запускается только после того, как отбежали все потоки на источниках, например, в ядре. Как это работает:
Каждые 5 минут запускается мониторинговый поток, который запускает кучу селектов и проверяет готовы ли источники.
Код там был примерно такой:
-- проверка логов за сегодня по каждой таблице
select count(t2.job_id)
from control.workflow t1 inner join control.log_loading t2 ...
where t1.workflow_name = t2.workflow_name
and t2.loading_id = ($$p_ loading_id)
and t2.status = 'succeeded'
...
and t1.table_name = 'table_name'
and t2.operation_day = to_date('$$p_operation_day","yyyymmdd')
having count(t2.job_id) >=
-- смотрим сколько всего потоков должно грузить таблицу (число фиксированное)
(select count(workflow_name)
from control.md_workflow t1
where table_owner = 'table_owner'
and table_name = 'table_name')
В этом запросе у нас идет сравнение по каждой таблице-источнику за отчетный день – сколько отработало сегодня потоков для ее загрузки и сколько потоков вообще грузит таблицу. Пока у нас все потоки за сегодня не прогрузят таблицу, проверочный select выдаст 0 строк. И потоки в слое витрин данных не грузят свои таблицы, пока не готовы их источники (пока в результате запроса нет строк).
Если в результате какого-нибудь select-a у нас есть число ( чаще, просто 1, тк в основном одну таблицу грузит один поток), то значит этот флаг пришел. Как только все флаги для определенного потока пришли, запускается расчет таблицы из слоя витрин.
Я не скажу, что это хорошая система. Это скорее легаси, сейчас делается по-другому. Но примерная система есть во многих «старых» компаниях.
В общем, GROUP BY для HAVING-a не обязателен.
Кстати, если у deepseek-а спросить об этом напрямую, он скажет, что можно использовать having без group by, но с оговоркой:
От себя добавлю - в Oracle это тоже работает. Так что всего проверяйте ответы нейронки😊
#Вопросы_с_собесов
Это один из самых популярных вопросов на стажера, джуна и иногда мидла de/da. Я думаю, практически все знают что нужно отвечать.
Вот, например, в тг канале @data_analysis_it был дан такой ответ https://t.me/data_analysis_it/83 :
Чем отличаются WHERE и HAVING?
WHERE
• GROUP BY не обязателен
• Применяется к отдельным строкам таблицы.
• Не может использовать агрегатные функции
HAVING
• GROUP BY обязателен
• Применяется к результатам агрегатных вычислений.
• Может использовать агрегатные функции
Все четко и понятно.
Deepseek даст такой краткий ответ:
Кратко:
1. WHERE:
• Фильтрует строки до группировки или агрегации.
• Работает с отдельными строками.
• Не может использоваться с агрегатными функциями.
2. HAVING:
• Фильтрует группы или результаты агрегации после группировки.
• Работает с группами строк или агрегатными функциями.
• Используется только с GROUP BY или агрегатными функциями.
Главное: WHERE — для строк, HAVING — для групп. 😊
Примерно тоже самое.
Это база, ее обязательно надо знать. В целом такого ответа на собеседовании будет достаточно.
НО! Но я вам хочу рассказать о важном нюансе, о котором очень много инженеров не знает:
HAVING можно использовать без GROUP BY!
Пример:
select max(campaign_id) from public.costs
having max(campaign_id)>2
--Результат 100.
select count(campaign_id) from public.costs
having count(campaign_id)>1000
--Результат 39300
В примере HAVING применяется не к группам, а ко всей таблице в целом, в данном случае группой является вся выборка. То есть в select-e выполняется просто функция, допустим count(*) , ко всем данным, но и еще можно сразу добавить фильтр по этому значению.
Вроде ничего важного, вряд ли кто-то таким образом будет использовать having без group by, просто прикольная фишка.
На самом деле данная фишка используется.
На моей прошлой работе, в одном красном банке, в архитектуре ETL была настроена система Eventwait-ов (флагов) таким образом:
Допустим у нас есть слой витрин данных, расчет таблиц в этом слое за сегодня запускается только после того, как отбежали все потоки на источниках, например, в ядре. Как это работает:
Каждые 5 минут запускается мониторинговый поток, который запускает кучу селектов и проверяет готовы ли источники.
Код там был примерно такой:
-- проверка логов за сегодня по каждой таблице
select count(t2.job_id)
from control.workflow t1 inner join control.log_loading t2 ...
where t1.workflow_name = t2.workflow_name
and t2.loading_id = ($$p_ loading_id)
and t2.status = 'succeeded'
...
and t1.table_name = 'table_name'
and t2.operation_day = to_date('$$p_operation_day","yyyymmdd')
having count(t2.job_id) >=
-- смотрим сколько всего потоков должно грузить таблицу (число фиксированное)
(select count(workflow_name)
from control.md_workflow t1
where table_owner = 'table_owner'
and table_name = 'table_name')
В этом запросе у нас идет сравнение по каждой таблице-источнику за отчетный день – сколько отработало сегодня потоков для ее загрузки и сколько потоков вообще грузит таблицу. Пока у нас все потоки за сегодня не прогрузят таблицу, проверочный select выдаст 0 строк. И потоки в слое витрин данных не грузят свои таблицы, пока не готовы их источники (пока в результате запроса нет строк).
Если в результате какого-нибудь select-a у нас есть число ( чаще, просто 1, тк в основном одну таблицу грузит один поток), то значит этот флаг пришел. Как только все флаги для определенного потока пришли, запускается расчет таблицы из слоя витрин.
Я не скажу, что это хорошая система. Это скорее легаси, сейчас делается по-другому. Но примерная система есть во многих «старых» компаниях.
В общем, GROUP BY для HAVING-a не обязателен.
Кстати, если у deepseek-а спросить об этом напрямую, он скажет, что можно использовать having без group by, но с оговоркой:
В большинстве СУБД (например, PostgreSQL, MySQL) это допустимо, но в некоторых (например, Oracle) может вызвать ошибку»
От себя добавлю - в Oracle это тоже работает. Так что всего проверяйте ответы нейронки😊
#Вопросы_с_собесов