Найти тему
Идеальный блокчейн

SQL. Практика баз данных для хипстеров. Story #6

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

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

Содержание беседы #6:

Тема 2. Язык структурированных запросов

Раздел 2.1 Понятие Стандарта ANSI-SQL

Пункт 2.1.2 Основные команды языка (Расширенное понимание Group By, Having)

Мы уже рассматривали назначение различных агрегатов (получение суммы по полю или же количества записей). Однако цель у агрегата всегда одна – вычислить агрегирующие значения по одной или нескольким группам. Типичная задача звучит так: Вычислить для каждого Предмета что-то (не «вывести предметы такие-то», а именно "вычислить").

Рассмотрим таблицу «Продажи» с полями: название филиала, дата отчетного дня, сумма дохода.

Задача №1: вычислить для каждого филиала сумму дохода за всё время.

Select FiLiaL, sum(SumDohod)
From Prodazhi
Group by FiLiaL

Задача №2: вывести суммы общего дохода только по тем филиалам, где эта сумма более 1 млн.

Select FiLiaL, sum(SumDohod)
From Prodazhi
Group by FiLiaL
Having sum(SumDohod) >1000000

Задача №3: вывести данные по всем филиалам за дни, когда прибыль была выше средней суммы дохода за день по этому филиалу.

Select A.FiLiaL, A.Date, A.SumDohod
From Prodazhi as A
Where A.SumDohod > (Select Avg(B.SumDohod)
From Prodazhi as B
Where B.FiLiaL = A.FiLiaL
)

Теперь самое любопытное: использование подзапроса с агрегатом в разделе Having.

Задача №4: вывести сумму общего дохода только для тех филиалов, которые работали в последний отчетный день.

Есть желание решить задачу объединением решений первой и второй задач:

Select FiLiaL, sum(SumDohod)
From Prodazhi as A
Where A.Date = (Select Max(B.Date)
From Prodazhi as B)
Group by FiLiaL

Однако это неверно. Потому что мы возьмем только выручку последнего дня. Мы не можем поставить ограничение на дату в разделе Where. Именно для решения таких задач и есть как бы еще один Where уже после подсчетов по группировке – Having, где нам никто не мешает вместо значения поставить целый подзапрос с агрегатом. Правильное решение следующее:

Select A.FiLiaL, Sum(A.SumDohod)
From Prodazhi as A
Group by A.FiLiaL
Having Max(A.Date) = (Select Max(B.Date)
From Prodazhi as B)

Итоговые замечания по агрегатам.

Агрегат может быть использован и без группировки: когда нужна общая цифра без выделения отдельных значений группы. Чаще всего подзапрос с агрегатом без группировки используется именно в разделе Where.

И наоборот, группировка может быть использована без агрегата – результат идентичен опции Distinct.

Агрегаты и группировки позволяют использовать в логических условиях данные, которые в явном виде в базе не хранятся, а существуют только как вычислимые статистические показатели.

Не страшно, если после прочтения беседы останется чувство недопонимания. Пожалуй, агрегаты - самая сложная тема при базовом овладении языком. Чтобы обнадежить вашу бороду, скажу, что лично знаю как минимум одного хорошего программиста SQL, который вовсе не использует операторы group by и having в работе, поскольку до конца их не понимает. И он успешно обходится без них.

Спасибо, что дочитали до конца! Любите друг друга... и базы данных)

Автор: Щукин Андрей (vk.com/faustonly), Санкт-Петербург. Дата публикации: 01.05.2018