1 added
1 removed
Original
2026-01-01
Modified
2026-02-21
1
<p><a>#статьи</a></p>
1
<p><a>#статьи</a></p>
2
<ul><li>26 июн 2024</li>
2
<ul><li>26 июн 2024</li>
3
<li>0</li>
3
<li>0</li>
4
</ul><p>Рассказываем, как производить агрегатные вычисления и не терять исходные строки.</p>
4
</ul><p>Рассказываем, как производить агрегатные вычисления и не терять исходные строки.</p>
5
<p>Иллюстрация: Оля Ежак для Skillbox Media</p>
5
<p>Иллюстрация: Оля Ежак для Skillbox Media</p>
6
<p>Программист, консультант, специалист по документированию. Легко и доступно рассказывает о сложных вещах в программировании и дизайне.</p>
6
<p>Программист, консультант, специалист по документированию. Легко и доступно рассказывает о сложных вещах в программировании и дизайне.</p>
7
<p>Оконные функции в SQL (от англ. window function) - это особый класс функций, позволяющий производить вычисления по определённым группам строк в базе данных. При этом они не объединяют строки в одну, а возвращают столько же, сколько было на входе.</p>
7
<p>Оконные функции в SQL (от англ. window function) - это особый класс функций, позволяющий производить вычисления по определённым группам строк в базе данных. При этом они не объединяют строки в одну, а возвращают столько же, сколько было на входе.</p>
8
<p>Эти функции удобно использовать для отчётов, анализа данных, финансового моделирования и других задач, где нужно видеть результаты в контексте исходных данных. С их помощью можно выполнять различные вычисления для набора строк: подсчитывать среднее число, сумму и многие другое.</p>
8
<p>Эти функции удобно использовать для отчётов, анализа данных, финансового моделирования и других задач, где нужно видеть результаты в контексте исходных данных. С их помощью можно выполнять различные вычисления для набора строк: подсчитывать среднее число, сумму и многие другое.</p>
9
<p>Всё самое важное об оконных функциях в SQL:</p>
9
<p>Всё самое важное об оконных функциях в SQL:</p>
10
<ul><li><a>таблица для примеров</a>;</li>
10
<ul><li><a>таблица для примеров</a>;</li>
11
<li><a>синтаксис оконных функций</a>;</li>
11
<li><a>синтаксис оконных функций</a>;</li>
12
<li><a>классы оконных функций</a>.</li>
12
<li><a>классы оконных функций</a>.</li>
13
</ul><p><strong>ЭКСПЕРТ</strong></p>
13
</ul><p><strong>ЭКСПЕРТ</strong></p>
14
<p>Разработчик-фрилансер. Занимается iOS-разработкой с 2011 года. Вела курс по Swift в Астраханском государственном университете. Программный директор и эксперт по мобильной разработке в Skillbox.</p>
14
<p>Разработчик-фрилансер. Занимается iOS-разработкой с 2011 года. Вела курс по Swift в Астраханском государственном университете. Программный директор и эксперт по мобильной разработке в Skillbox.</p>
15
<p>С 2016 года также занималась управлением проектами в мобильной разработке.</p>
15
<p>С 2016 года также занималась управлением проектами в мобильной разработке.</p>
16
<p>Создадим таблицу sport_sales, содержащую продажи магазина спортивных товаров по отделам. Включим в неё следующие поля:</p>
16
<p>Создадим таблицу sport_sales, содержащую продажи магазина спортивных товаров по отделам. Включим в неё следующие поля:</p>
17
<ul><li>id - уникальный идентификатор каждой записи;</li>
17
<ul><li>id - уникальный идентификатор каждой записи;</li>
18
<li>sale_date - дата продаж по каждому отделу;</li>
18
<li>sale_date - дата продаж по каждому отделу;</li>
19
<li>department - наименование отдела;</li>
19
<li>department - наименование отдела;</li>
20
<li>sales - количество продаж по каждому отделу за день.</li>
20
<li>sales - количество продаж по каждому отделу за день.</li>
21
</ul><p>Таблицу можно создать с помощью следующего запроса:</p>
21
</ul><p>Таблицу можно создать с помощью следующего запроса:</p>
22
CREATE TABLE IF NOT EXISTS sport_sales ( id integer primary key, sale_date date, department varchar(50), sales integer );<p>А для заполнения таблицы данными используем следующий код:</p>
22
CREATE TABLE IF NOT EXISTS sport_sales ( id integer primary key, sale_date date, department varchar(50), sales integer );<p>А для заполнения таблицы данными используем следующий код:</p>
23
insert into sport_sales (id, sale_date, department, sales) values (1, 2024-02-01, 'Shoes', 6), (2, 2024-02-01, Clothing', 5), (3, 2024-02-01, Equipment', 10), (4, 2024-02-02, Clothing', 6), (5, 2024-02-02, Clothing', 6), (5, 2024-02-02, Equipment', 4), (6, 2024-02-01, 'Shoes', 4), (7, 2024-02-03, 'Shoes', 8), (8, 2024-02-03, Equipment', 10), (9, 2024-02-01, Clothing', 4);<p>В результате получим вот такую таблицу базы данных, будем использовать её:</p>
23
insert into sport_sales (id, sale_date, department, sales) values (1, 2024-02-01, 'Shoes', 6), (2, 2024-02-01, Clothing', 5), (3, 2024-02-01, Equipment', 10), (4, 2024-02-02, Clothing', 6), (5, 2024-02-02, Clothing', 6), (5, 2024-02-02, Equipment', 4), (6, 2024-02-01, 'Shoes', 4), (7, 2024-02-03, 'Shoes', 8), (8, 2024-02-03, Equipment', 10), (9, 2024-02-01, Clothing', 4);<p>В результате получим вот такую таблицу базы данных, будем использовать её:</p>
24
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong>12024-02-01Shoes622024-02-01Clothing532024-02-01Equipment1042024-02-02Clothing652024-02-02Equipment462024-02-02Shoes472024-02-03Shoes882024-02-03Equipment1092024-02-03Clothing4<p><strong>?️ Технические детали</strong></p>
24
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong>12024-02-01Shoes622024-02-01Clothing532024-02-01Equipment1042024-02-02Clothing652024-02-02Equipment462024-02-02Shoes472024-02-03Shoes882024-02-03Equipment1092024-02-03Clothing4<p><strong>?️ Технические детали</strong></p>
25
<p>Синтаксис оконных функций может различаться в разных реализациях SQL. Некоторые функции могут называться иначе или их может не быть вовсе. Запросы в этой статье показаны на примере PL\SQL - диалекта, который используется в <a>базах данных под управлением Oracle DB</a>.</p>
25
<p>Синтаксис оконных функций может различаться в разных реализациях SQL. Некоторые функции могут называться иначе или их может не быть вовсе. Запросы в этой статье показаны на примере PL\SQL - диалекта, который используется в <a>базах данных под управлением Oracle DB</a>.</p>
26
<p>В общем виде синтаксис оконных функций выглядит так:</p>
26
<p>В общем виде синтаксис оконных функций выглядит так:</p>
27
<window_function>(arguments) OVER ([Partitioning] [Ordering] [Frame])<p>Детально разберём структуру:</p>
27
<window_function>(arguments) OVER ([Partitioning] [Ordering] [Frame])<p>Детально разберём структуру:</p>
28
<ul><li><window_function_name> - имя оконной функции, например ROW_NUMBER(), RANK(), DENSE_RANK() и другие.</li>
28
<ul><li><window_function_name> - имя оконной функции, например ROW_NUMBER(), RANK(), DENSE_RANK() и другие.</li>
29
<li>(arguments) - аргументы функции, например имя столбца, по которому происходит расчёт.</li>
29
<li>(arguments) - аргументы функции, например имя столбца, по которому происходит расчёт.</li>
30
<li>OVER() - ключевое слово, которое определяет, как оконная функция будет применятся к набору данных.</li>
30
<li>OVER() - ключевое слово, которое определяет, как оконная функция будет применятся к набору данных.</li>
31
<li>[Partitioning] - определяет критерий, по которому строки делятся на подгруппы. Это необязательный компонент.</li>
31
<li>[Partitioning] - определяет критерий, по которому строки делятся на подгруппы. Это необязательный компонент.</li>
32
<li>[Ordering] - указывает порядок строк в каждой подгруппе, что важно для таких функций, как RANK(), ROW_NUMBER() и других. Этот элемент тоже необязателен.</li>
32
<li>[Ordering] - указывает порядок строк в каждой подгруппе, что важно для таких функций, как RANK(), ROW_NUMBER() и других. Этот элемент тоже необязателен.</li>
33
<li>[Frame] - задаёт "фрейм" строк относительно текущей. Как правило, используется с ключевыми словами ROWS или RANGE.</li>
33
<li>[Frame] - задаёт "фрейм" строк относительно текущей. Как правило, используется с ключевыми словами ROWS или RANGE.</li>
34
</ul><p>Рассмотрим подробнее эти компоненты.</p>
34
</ul><p>Рассмотрим подробнее эти компоненты.</p>
35
<p>Параметр, который позволяет разделить данные на группы, внутри которых будет применяться оконная функция. PARTITION BY действует аналогично GROUP BY в агрегатных функциях, но в оконных функциях результат возвращается для каждой строки входных данных.</p>
35
<p>Параметр, который позволяет разделить данные на группы, внутри которых будет применяться оконная функция. PARTITION BY действует аналогично GROUP BY в агрегатных функциях, но в оконных функциях результат возвращается для каждой строки входных данных.</p>
36
<p>Например, рассмотрим, как работает запрос с группировкой GROUP BY, считающий суммарные продажи за период по каждому отделу:</p>
36
<p>Например, рассмотрим, как работает запрос с группировкой GROUP BY, считающий суммарные продажи за период по каждому отделу:</p>
37
SELECT department, sum(sales) AS sum_sales FROM sport_sales GROUP BY department ORDER BY department;<p>В результате получим:</p>
37
SELECT department, sum(sales) AS sum_sales FROM sport_sales GROUP BY department ORDER BY department;<p>В результате получим:</p>
38
<strong>department</strong><strong>sum_sales</strong>Clothing15Equipment24Shoes18<p>Этот запрос выводит в столбце sum_sales сумму продаж по каждому отделу.</p>
38
<strong>department</strong><strong>sum_sales</strong>Clothing15Equipment24Shoes18<p>Этот запрос выводит в столбце sum_sales сумму продаж по каждому отделу.</p>
39
<p>Теперь используем оконную функцию:</p>
39
<p>Теперь используем оконную функцию:</p>
40
-
SELECT id, sale_date, department, sales, sum(sale) OVER(PARTITION BY department) AS sum_sales FROM sport_sales4 ORDER BY department, sale_date;<p>Результат будет таким:</p>
40
+
SELECT id, sale_date, department, sales, sum(sale) OVER(PARTITION BY department) AS sum_sales FROM sport_sales4 ORDER BY department, sale_date;<p>Результат будет ��аким:</p>
41
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong><strong>sum_sales</strong>22024-02-01Clothing51542024-02-02Clothing61592024-02-03Clothing41532024-02-01Equipment102452024-02-02Equipment42482024-02-03Equipment102412024-02-01Shoes61862024-02-02Shoes41872024-02-03Shoes818<p>Этот запрос выводит продажи каждого отдела в столбце sales и суммарные продажи в столбце sum_sales. Все строки из исходной таблицы сохраняются, причём они сгруппированы по отделам.</p>
41
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong><strong>sum_sales</strong>22024-02-01Clothing51542024-02-02Clothing61592024-02-03Clothing41532024-02-01Equipment102452024-02-02Equipment42482024-02-03Equipment102412024-02-01Shoes61862024-02-02Shoes41872024-02-03Shoes818<p>Этот запрос выводит продажи каждого отдела в столбце sales и суммарные продажи в столбце sum_sales. Все строки из исходной таблицы сохраняются, причём они сгруппированы по отделам.</p>
42
<p>Ключевое слово ORDER BY определяет, как данные будут упорядочены при применении оконной функции.</p>
42
<p>Ключевое слово ORDER BY определяет, как данные будут упорядочены при применении оконной функции.</p>
43
<p>Для определения порядка строк используются ключевые слова ASC и DESC:</p>
43
<p>Для определения порядка строк используются ключевые слова ASC и DESC:</p>
44
<ul><li>ASC - сортировка по возрастанию. Это значение по умолчанию. Упорядочивание от наименьшего значения к наибольшему.</li>
44
<ul><li>ASC - сортировка по возрастанию. Это значение по умолчанию. Упорядочивание от наименьшего значения к наибольшему.</li>
45
<li>DESC - сортировка по убыванию. Упорядочивание от наибольшего значения к наименьшему.</li>
45
<li>DESC - сортировка по убыванию. Упорядочивание от наибольшего значения к наименьшему.</li>
46
</ul><p>ORDER BY может включать несколько колонок. Например, ORDER BY sale_date ASC, sale DESC сначала упорядочивает данные отделов по датам в порядке возрастания, а затем по продажам в порядке убывания.</p>
46
</ul><p>ORDER BY может включать несколько колонок. Например, ORDER BY sale_date ASC, sale DESC сначала упорядочивает данные отделов по датам в порядке возрастания, а затем по продажам в порядке убывания.</p>
47
<p>Составим запрос с использованием функции RANK(), которая присваивает ранг каждой строке в зависимости от значения в столбце sale. Отделу с наибольшими продажами за день присваивается ранг 1, с наименьшими - ранг 3. Значения столбца sale_date сгруппируем по возрастанию, а sales - по убыванию:</p>
47
<p>Составим запрос с использованием функции RANK(), которая присваивает ранг каждой строке в зависимости от значения в столбце sale. Отделу с наибольшими продажами за день присваивается ранг 1, с наименьшими - ранг 3. Значения столбца sale_date сгруппируем по возрастанию, а sales - по убыванию:</p>
48
SELECT id, sale_date, department, sales, RANK() OVER(PARTITION BY sale_date ORDER BY sale_date ASC, sales DESC) AS rank FROM sport_sales;<p>Вот какую таблицу получим в итоге:</p>
48
SELECT id, sale_date, department, sales, RANK() OVER(PARTITION BY sale_date ORDER BY sale_date ASC, sales DESC) AS rank FROM sport_sales;<p>Вот какую таблицу получим в итоге:</p>
49
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong><strong>rank</strong>32024-02-01Equipment10112024-02-01Shoes6222024-02-01Clothing5342024-02-02Clothing6152024-02-02Equipment4262024-02-02Shoes4282024-02-03Equipment10172024-02-03Shoes8292024-02-03Clothing43<p>Ключевые слова ROWS и RANGE определяют, какие строки окна будут учитываться при выполнении расчётов. Они устанавливают "фрейм" окна - набор строк относительно текущей строки, который будет использоваться для вычислений.</p>
49
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong><strong>rank</strong>32024-02-01Equipment10112024-02-01Shoes6222024-02-01Clothing5342024-02-02Clothing6152024-02-02Equipment4262024-02-02Shoes4282024-02-03Equipment10172024-02-03Shoes8292024-02-03Clothing43<p>Ключевые слова ROWS и RANGE определяют, какие строки окна будут учитываться при выполнении расчётов. Они устанавливают "фрейм" окна - набор строк относительно текущей строки, который будет использоваться для вычислений.</p>
50
<p>ROWS задаёт границы окна в пределах определённого количества строк до или после текущей строки. Например, ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING указывает, что окно включает строку перед текущей, текущую и строку после. На их основании будет вычисляться функция.</p>
50
<p>ROWS задаёт границы окна в пределах определённого количества строк до или после текущей строки. Например, ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING указывает, что окно включает строку перед текущей, текущую и строку после. На их основании будет вычисляться функция.</p>
51
<p>Напишем запрос, который суммирует продажи в текущей, предыдущей и последующей строках и размещает полученные суммы в столбце sum_sales:</p>
51
<p>Напишем запрос, который суммирует продажи в текущей, предыдущей и последующей строках и размещает полученные суммы в столбце sum_sales:</p>
52
SELECT id, sale_date, department, sales, SUM(sale) OVER (ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS sum_sales FROM sport_sales;<p>В результате получим:</p>
52
SELECT id, sale_date, department, sales, SUM(sale) OVER (ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS sum_sales FROM sport_sales;<p>В результате получим:</p>
53
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong><strong>sum_sales</strong>12024-02-01Shoes61122024-02-01Clothing52132024-02-01Equipment102142024-02-02Clothing62052024-02-02Equipment41462024-02-02Shoes41672024-02-03Shoes82282024-02-03Equipment102292024-02-03Clothing414<p>В таблице выше данные сгруппированы по датам, и в столбце sum_sales считаются так:</p>
53
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong><strong>sum_sales</strong>12024-02-01Shoes61122024-02-01Clothing52132024-02-01Equipment102142024-02-02Clothing62052024-02-02Equipment41462024-02-02Shoes41672024-02-03Shoes82282024-02-03Equipment102292024-02-03Clothing414<p>В таблице выше данные сгруппированы по датам, и в столбце sum_sales считаются так:</p>
54
<ul><li>Когда текущая - первая строка, суммируются продажи из первой и второй строки.</li>
54
<ul><li>Когда текущая - первая строка, суммируются продажи из первой и второй строки.</li>
55
<li>Когда текущая - вторая строка, суммируются продажи из первой, второй и третьей строки и так далее.</li>
55
<li>Когда текущая - вторая строка, суммируются продажи из первой, второй и третьей строки и так далее.</li>
56
</ul><p>RANGE устанавливает границы окна на основе значений заданного столбца, а не на физическом расположении строк, как это делает ROWS. Он группирует вместе строки с одинаковыми или близкими значениями в указанном столбце сортировки.</p>
56
</ul><p>RANGE устанавливает границы окна на основе значений заданного столбца, а не на физическом расположении строк, как это делает ROWS. Он группирует вместе строки с одинаковыми или близкими значениями в указанном столбце сортировки.</p>
57
<p>То есть, когда вы используете RANGE вместе с ORDER BY, SQL обрабатывает окно для каждой строки, включая в него всё с соответствующими или сопоставимыми значениями столбца, указанного в ORDER BY. Это значит, что, если есть несколько строк с одинаковыми значениями в сортируемом столбце (например, одинаковые даты или отделы), они все будут включены в окно.</p>
57
<p>То есть, когда вы используете RANGE вместе с ORDER BY, SQL обрабатывает окно для каждой строки, включая в него всё с соответствующими или сопоставимыми значениями столбца, указанного в ORDER BY. Это значит, что, если есть несколько строк с одинаковыми значениями в сортируемом столбце (например, одинаковые даты или отделы), они все будут включены в окно.</p>
58
<p>Например, рассчитаем кумулятивную (накапливающуюся) сумму продаж по датам. Для этого напишем следующий запрос:</p>
58
<p>Например, рассчитаем кумулятивную (накапливающуюся) сумму продаж по датам. Для этого напишем следующий запрос:</p>
59
SELECT id, sale_date, department, sales, SUM(sale) OVER ( ORDER BY sale_date RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS cumulative_sales FROM sport_sales;<p>В этом примере для каждой даты будут суммироваться все значения sale начиная от самой первой записи до текущей даты, включая все строки с датами, равными дате текущей.</p>
59
SELECT id, sale_date, department, sales, SUM(sale) OVER ( ORDER BY sale_date RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS cumulative_sales FROM sport_sales;<p>В этом примере для каждой даты будут суммироваться все значения sale начиная от самой первой записи до текущей даты, включая все строки с датами, равными дате текущей.</p>
60
<p>В результате получим:</p>
60
<p>В результате получим:</p>
61
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong>cumulative_sales12024-02-01Shoes62122024-02-01Clothing52132024-02-01Equipment102142024-02-02Clothing63552024-02-02Equipment43562024-02-02Shoes43572024-02-03Shoes85782024-02-03Equipment105792024-02-03Clothing457<p>RANGE может быть полезен, когда нужно производить вычисления на группах данных, которые логически связаны (например, записи с теми же датами или близкими ценами).</p>
61
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong>cumulative_sales12024-02-01Shoes62122024-02-01Clothing52132024-02-01Equipment102142024-02-02Clothing63552024-02-02Equipment43562024-02-02Shoes43572024-02-03Shoes85782024-02-03Equipment105792024-02-03Clothing457<p>RANGE может быть полезен, когда нужно производить вычисления на группах данных, которые логически связаны (например, записи с теми же датами или близкими ценами).</p>
62
<p>В SQL есть множество оконных функций, которые упрощают работу с данными. С их помощью можно быстро проводить сложные вычисления по группам строк, связанных с текущей. Основные оконные функции можно разделить на три большие группы.</p>
62
<p>В SQL есть множество оконных функций, которые упрощают работу с данными. С их помощью можно быстро проводить сложные вычисления по группам строк, связанных с текущей. Основные оконные функции можно разделить на три большие группы.</p>
63
<p>Агрегатные функции - позволяют выполнять суммирование, подсчёт, нахождение максимумов и минимумов и средних значений. Они производят вычисления над набором строк в окне и возвращают одно результирующее значение:</p>
63
<p>Агрегатные функции - позволяют выполнять суммирование, подсчёт, нахождение максимумов и минимумов и средних значений. Они производят вычисления над набором строк в окне и возвращают одно результирующее значение:</p>
64
<ul><li>SUM(column_name) - возвращает сумму выбранных значений;</li>
64
<ul><li>SUM(column_name) - возвращает сумму выбранных значений;</li>
65
<li>AVG(column_name) - вычисляет среднее значение;</li>
65
<li>AVG(column_name) - вычисляет среднее значение;</li>
66
<li>MAX(column_name) и MIN(column_name) - возвращают максимальное и минимальное значение соответственно;</li>
66
<li>MAX(column_name) и MIN(column_name) - возвращают максимальное и минимальное значение соответственно;</li>
67
<li>COUNT(column_name) - находит количество значений.</li>
67
<li>COUNT(column_name) - находит количество значений.</li>
68
</ul><p>В качестве примера применим агрегатные функции к продажам в отделах для каждой даты так, чтобы каждая строка в окне сохранила исходные значения:</p>
68
</ul><p>В качестве примера применим агрегатные функции к продажам в отделах для каждой даты так, чтобы каждая строка в окне сохранила исходные значения:</p>
69
SELECT id, sale_date, department, sales, AVG(sales) OVER (PARTITION BY sale_date) as avg_s, SUM(sales) OVER (PARTITION BY sale_date) as sum_s, MAX(sales)OVER (PARTITION BY sale_date) as max_s, MIN(sales)OVER (PARTITION BY sale_date) as min_s, COUNT(sales) OVER (PARTITION BY sale_date) as count_s FROM sport_sales;<p>В результате получим следующую таблицу:</p>
69
SELECT id, sale_date, department, sales, AVG(sales) OVER (PARTITION BY sale_date) as avg_s, SUM(sales) OVER (PARTITION BY sale_date) as sum_s, MAX(sales)OVER (PARTITION BY sale_date) as max_s, MIN(sales)OVER (PARTITION BY sale_date) as min_s, COUNT(sales) OVER (PARTITION BY sale_date) as count_s FROM sport_sales;<p>В результате получим следующую таблицу:</p>
70
<strong>id</strong><strong>sale_</strong><strong>date</strong><strong>department</strong><strong>sale</strong><strong>avg_s</strong><strong>sum_s</strong><strong>max_s</strong><strong>min_s</strong><strong>count_s</strong>12024-02-01Shoes67.021105322024-02-01Clothing57.021105332024-02-01Equipment107.021105342024-02-02Clothing64.71464352024-02-02Equipment44.71464362024-02-02Shoes44.71464372024-02-03Shoes87.322104382024-02-03Equipment107.322104392024-02-03Clothing47.3221043<p>Важно отметить, что агрегатные функции чувствительны к NULL. К примеру, AVG() и SUM() игнорируют такие значения, а COUNT() - считает все строки, даже с NULL.</p>
70
<strong>id</strong><strong>sale_</strong><strong>date</strong><strong>department</strong><strong>sale</strong><strong>avg_s</strong><strong>sum_s</strong><strong>max_s</strong><strong>min_s</strong><strong>count_s</strong>12024-02-01Shoes67.021105322024-02-01Clothing57.021105332024-02-01Equipment107.021105342024-02-02Clothing64.71464352024-02-02Equipment44.71464362024-02-02Shoes44.71464372024-02-03Shoes87.322104382024-02-03Equipment107.322104392024-02-03Clothing47.3221043<p>Важно отметить, что агрегатные функции чувствительны к NULL. К примеру, AVG() и SUM() игнорируют такие значения, а COUNT() - считает все строки, даже с NULL.</p>
71
<p>Функции ранжирования предоставляют способы оценки позиции каждой строки среди своих соседей в определённом порядке. Они полезны, когда необходимо определить ранги в наборе данных.</p>
71
<p>Функции ранжирования предоставляют способы оценки позиции каждой строки среди своих соседей в определённом порядке. Они полезны, когда необходимо определить ранги в наборе данных.</p>
72
<p>Основные функции ранжирования:</p>
72
<p>Основные функции ранжирования:</p>
73
<p><strong>Функция</strong>RANK()<strong>.</strong>Присваивает ранг каждой строке в разделе окна. Если строки одинаковы, они получают одинаковый ранг, но следующий ранг будет увеличен на количество строк с одинаковым рангом.</p>
73
<p><strong>Функция</strong>RANK()<strong>.</strong>Присваивает ранг каждой строке в разделе окна. Если строки одинаковы, они получают одинаковый ранг, но следующий ранг будет увеличен на количество строк с одинаковым рангом.</p>
74
<p>В примере ниже SQL-запрос присваивает строкам ранги в порядке возрастания числа продаж. Если количество продаж одинаковое (id 5 и 6), то будет присвоен ранг 1, а следующей по порядку строке (id 4) - ранг 3:</p>
74
<p>В примере ниже SQL-запрос присваивает строкам ранги в порядке возрастания числа продаж. Если количество продаж одинаковое (id 5 и 6), то будет присвоен ранг 1, а следующей по порядку строке (id 4) - ранг 3:</p>
75
SELECT id, sale_date, department, sales, RANK() OVER (PARTITION BY sale_date ORDER BY sales) AS rank_s FROM sport_sales;<p>Так выглядит таблица с результатом запроса:</p>
75
SELECT id, sale_date, department, sales, RANK() OVER (PARTITION BY sale_date ORDER BY sales) AS rank_s FROM sport_sales;<p>Так выглядит таблица с результатом запроса:</p>
76
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong><strong>rank_s</strong>22024-02-01Clothing5112024-02-01Shoes6232024-02-01Equipment10352024-02-02Equipment4162024-02-02Shoes4142024-02-02Clothing6392024-02-03Clothing4172024-02-03Shoes8282024-02-03Equipment103<p><strong>Функция</strong><strong>DENSE_RANK()</strong><strong>.</strong>Похожа на RANK(), но работает "плотнее". Это значит, что следующий ранг увеличивается на 1, независимо от количества строк с одинаковым рангом.</p>
76
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong><strong>rank_s</strong>22024-02-01Clothing5112024-02-01Shoes6232024-02-01Equipment10352024-02-02Equipment4162024-02-02Shoes4142024-02-02Clothing6392024-02-03Clothing4172024-02-03Shoes8282024-02-03Equipment103<p><strong>Функция</strong><strong>DENSE_RANK()</strong><strong>.</strong>Похожа на RANK(), но работает "плотнее". Это значит, что следующий ранг увеличивается на 1, независимо от количества строк с одинаковым рангом.</p>
77
<p>Напишем простой запрос с использованием функции DENSE_RANK():</p>
77
<p>Напишем простой запрос с использованием функции DENSE_RANK():</p>
78
SELECT id, sale_date, department, sales, DENSE_RANK() OVER (PARTITION BY sale_date ORDER BY sales) AS dn_rank_s FROM sport_sales;<p>В этом примере SQL-запрос также присваивает строкам ранг в порядке возрастания количества продаж. Если количество продаж одинаково (id 5 и 6), то будет присвоен ранг 1, а следующей по порядку строке (id 4) - ранг 2. Вот как это отражается в таблице:</p>
78
SELECT id, sale_date, department, sales, DENSE_RANK() OVER (PARTITION BY sale_date ORDER BY sales) AS dn_rank_s FROM sport_sales;<p>В этом примере SQL-запрос также присваивает строкам ранг в порядке возрастания количества продаж. Если количество продаж одинаково (id 5 и 6), то будет присвоен ранг 1, а следующей по порядку строке (id 4) - ранг 2. Вот как это отражается в таблице:</p>
79
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong><strong>dn_rank_s</strong>22024-02-01Clothing5112024-02-01Shoes6232024-02-01Equipment10352024-02-02Equipment4162024-02-02Shoes4142024-02-02Clothing6292024-02-03Clothing4172024-02-03Shoes8282024-02-03Equipment103<p><strong>Функция</strong><strong>ROW_NUMBER()</strong><strong>.</strong>Присваивает уникальный порядковый номер каждой строке в разделе окна.</p>
79
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong><strong>dn_rank_s</strong>22024-02-01Clothing5112024-02-01Shoes6232024-02-01Equipment10352024-02-02Equipment4162024-02-02Shoes4142024-02-02Clothing6292024-02-03Clothing4172024-02-03Shoes8282024-02-03Equipment103<p><strong>Функция</strong><strong>ROW_NUMBER()</strong><strong>.</strong>Присваивает уникальный порядковый номер каждой строке в разделе окна.</p>
80
<p>SQL-запрос выглядит следующим образом:</p>
80
<p>SQL-запрос выглядит следующим образом:</p>
81
SELECT id, sale_date, department, sale, ROW_NUMBER() OVER (PARTITION BY sale_date ORDER BY department) AS row_n FROM sport_sales;<p>В результате все данные рассортированы по датам продаж и отмечены уникальными номерами:</p>
81
SELECT id, sale_date, department, sale, ROW_NUMBER() OVER (PARTITION BY sale_date ORDER BY department) AS row_n FROM sport_sales;<p>В результате все данные рассортированы по датам продаж и отмечены уникальными номерами:</p>
82
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong><strong>r<strong>ow_n</strong></strong>22024-02-01Clothing5132024-02-01Equipment10212024-02-01Shoes6342024-02-02Clothing6152024-02-02Equipment4262024-02-02Shoes4392024-02-03Clothing4182024-02-03Equipment10272024-02-03Shoes83<p>Функции смещения позволяют выполнять операции над текущей строкой, в зависимости от других строк в окне. Они бывают полезны, когда нужно анализировать последовательности или временные ряды данных.</p>
82
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong><strong>r<strong>ow_n</strong></strong>22024-02-01Clothing5132024-02-01Equipment10212024-02-01Shoes6342024-02-02Clothing6152024-02-02Equipment4262024-02-02Shoes4392024-02-03Clothing4182024-02-03Equipment10272024-02-03Shoes83<p>Функции смещения позволяют выполнять операции над текущей строкой, в зависимости от других строк в окне. Они бывают полезны, когда нужно анализировать последовательности или временные ряды данных.</p>
83
<p>Основные функции смещения:</p>
83
<p>Основные функции смещения:</p>
84
<p><strong>Функция</strong><strong>LEAD()</strong><strong>.</strong>Позволяет заглянуть вперёд на определённое количество строк от текущей и получить значение из столбца в этих строках.</p>
84
<p><strong>Функция</strong><strong>LEAD()</strong><strong>.</strong>Позволяет заглянуть вперёд на определённое количество строк от текущей и получить значение из столбца в этих строках.</p>
85
<p>К примеру, запрос может выглядеть следующим образом:</p>
85
<p>К примеру, запрос может выглядеть следующим образом:</p>
86
SELECT id, sale_date, department, sales, LEAD(sales, 1) OVER (PARTITION BY department ORDER BY sale_date) AS next_day_s FROM sport_sales;<p>В результате для каждого отдела запрос возвращает продажи текущего дня (sales) и следующего (next_day_s):</p>
86
SELECT id, sale_date, department, sales, LEAD(sales, 1) OVER (PARTITION BY department ORDER BY sale_date) AS next_day_s FROM sport_sales;<p>В результате для каждого отдела запрос возвращает продажи текущего дня (sales) и следующего (next_day_s):</p>
87
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong><strong>next_day_s</strong>22024-02-01Clothing5642024-02-02Clothing6492024-02-03Clothing4None32024-02-01Equipment10452024-02-02Equipment41082024-02-03Equipment10None12024-02-01Shoes6462024-02-02Shoes4872024-02-03Shoes8None<p><strong>Функция</strong><strong>LAG()</strong><strong>.</strong>Похожа на LEAD(), но, вместо того чтобы "заглядывать вперёд", эта функция "смотрит назад" на определённое количество строк.</p>
87
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong><strong>next_day_s</strong>22024-02-01Clothing5642024-02-02Clothing6492024-02-03Clothing4None32024-02-01Equipment10452024-02-02Equipment41082024-02-03Equipment10None12024-02-01Shoes6462024-02-02Shoes4872024-02-03Shoes8None<p><strong>Функция</strong><strong>LAG()</strong><strong>.</strong>Похожа на LEAD(), но, вместо того чтобы "заглядывать вперёд", эта функция "смотрит назад" на определённое количество строк.</p>
88
<p>Здесь в каждой строке окна столбец sales покажет продажи текущего, а столбец last_day_s - продажи предыдущего дня для каждого отдела:</p>
88
<p>Здесь в каждой строке окна столбец sales покажет продажи текущего, а столбец last_day_s - продажи предыдущего дня для каждого отдела:</p>
89
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong><strong>last_day_s</strong>22024-02-01Clothing5None42024-02-02Clothing6592024-02-03Clothing4632024-02-01Equipment10None52024-02-02Equipment41082024-02-03Equipment10412024-02-01Shoes6None62024-02-02Shoes4672024-02-03Shoes84<p><strong>Функции</strong><strong>FIRST_VALUE() и</strong><strong>LAST_VALUE().</strong>Эти функции возвращают первое и последнее значение столбца в окне соответственно.</p>
89
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong><strong>last_day_s</strong>22024-02-01Clothing5None42024-02-02Clothing6592024-02-03Clothing4632024-02-01Equipment10None52024-02-02Equipment41082024-02-03Equipment10412024-02-01Shoes6None62024-02-02Shoes4672024-02-03Shoes84<p><strong>Функции</strong><strong>FIRST_VALUE() и</strong><strong>LAST_VALUE().</strong>Эти функции возвращают первое и последнее значение столбца в окне соответственно.</p>
90
<p>С помощью вот такого запроса можно вывести продажи текущего дня и продажи за первое и третье число для каждого отдела:</p>
90
<p>С помощью вот такого запроса можно вывести продажи текущего дня и продажи за первое и третье число для каждого отдела:</p>
91
SELECT id, sale_date, department, sale, FIRST_VALUE(sale) OVER (PARTITION BY department ORDER BY sale_date) AS first_sale, LAST_VALUE(sale) OVER (PARTITION BY department ORDER BY sale_date) AS last_sale FROM sport_sales;<p>Результат работы запроса выглядит так:</p>
91
SELECT id, sale_date, department, sale, FIRST_VALUE(sale) OVER (PARTITION BY department ORDER BY sale_date) AS first_sale, LAST_VALUE(sale) OVER (PARTITION BY department ORDER BY sale_date) AS last_sale FROM sport_sales;<p>Результат работы запроса выглядит так:</p>
92
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong><strong>first_sale</strong><strong>last_sale</strong>22024-02-01Clothing55442024-02-02Clothing65492024-02-03Clothing45432024-02-01Equipment10101052024-02-02Equipment4101082024-02-03Equipment10101012024-02-01Shoes66862024-02-02Shoes46872024-02-03Shoes868<p>Оконные функции делают SQL-запросы более гибкими и мощными. Они помогают избежать потерь информации, которая содержится в каждой строке исходных данных. А ещё выполняют различные расчёты с таблицами - например, ранжирование, суммирование или выведение статистики.</p>
92
<strong>id</strong><strong>sale_date</strong><strong>department</strong><strong>sales</strong><strong>first_sale</strong><strong>last_sale</strong>22024-02-01Clothing55442024-02-02Clothing65492024-02-03Clothing45432024-02-01Equipment10101052024-02-02Equipment4101082024-02-03Equipment10101012024-02-01Shoes66862024-02-02Shoes46872024-02-03Shoes868<p>Оконные функции делают SQL-запросы более гибкими и мощными. Они помогают избежать потерь информации, которая содержится в каждой строке исходных данных. А ещё выполняют различные расчёты с таблицами - например, ранжирование, суммирование или выведение статистики.</p>
93
<p>Оконные функции оперируют в контексте "окна" - подмножества таблицы и добавляют новую информацию в отдельные столбцы. Они позволяют избежать дополнительных запросов, что упрощает работу с базами данных и делает SQL-запросы более читаемыми.</p>
93
<p>Оконные функции оперируют в контексте "окна" - подмножества таблицы и добавляют новую информацию в отдельные столбцы. Они позволяют избежать дополнительных запросов, что упрощает работу с базами данных и делает SQL-запросы более читаемыми.</p>
94
<p>Data Science с нуля: пробуем профессии на практике за 5 дней</p>
94
<p>Data Science с нуля: пробуем профессии на практике за 5 дней</p>
95
<p>Вы разберётесь в трёх главных направлениях data science: машинном обучении, разработке на Python и визуализации данных. Решите, какая сфера вам ближе, и выполните 4 реальные задачи с данными.</p>
95
<p>Вы разберётесь в трёх главных направлениях data science: машинном обучении, разработке на Python и визуализации данных. Решите, какая сфера вам ближе, и выполните 4 реальные задачи с данными.</p>
96
<p><a>Пройти бесплатно</a></p>
96
<p><a>Пройти бесплатно</a></p>
97
<a><b>Попробуйте data science на бесплатном курсе</b>Пройдите курс по data science и изучите 3 направления в работе с данными. Решите, в какой сфере хотите развиваться дальше, и получите ценные подарки. Пройти курс →</a>
97
<a><b>Попробуйте data science на бесплатном курсе</b>Пройдите курс по data science и изучите 3 направления в работе с данными. Решите, в какой сфере хотите развиваться дальше, и получите ценные подарки. Пройти курс →</a>