--1
--С помощью оператора GROUP BY посчитайте количество курьеров мужского и женского пола в таблице couriers.
--Новую колонку с числом курьеров назовите couriers_count.
--Результат отсортируйте по этой колонке по возрастанию.

SELECT sex,
       count(courier_id) as couriers_count
FROM   couriers
GROUP BY sex
ORDER BY couriers_count;

--2
--Посчитайте количество созданных и отменённых заказов в таблице user_actions.
--Новую колонку с числом заказов назовите orders_count.
--Результат отсортируйте по числу заказов по возрастанию.

SELECT action,
       count (action) as orders_count
FROM   user_actions
GROUP BY 1
ORDER BY 2;

--3
--Используя группировку и функцию DATE_TRUNC, приведите все даты к началу месяца и посчитайте, сколько заказов было сделано в каждом из них.
--Расчёты проведите по таблице orders. Колонку с усечённой датой назовите month, колонку с количеством заказов — orders_count.
--Результат отсортируйте по месяцам — по возрастанию.

SELECT date_trunc ('month', creation_time) as month,
       count (order_id) as orders_count
FROM   orders
GROUP BY month
ORDER BY month;

--4
--Используя группировку и функцию DATE_TRUNC, приведите все даты к началу месяца и посчитайте, сколько заказов было сделано и сколько было отменено в каждом из них.
--В этот раз расчёты проведите по таблице user_actions. Колонку с усечённой датой назовите month, колонку с количеством заказов — orders_count.
--Результат отсортируйте сначала по месяцам — по возрастанию, затем по типу действия — тоже по возрастанию.

SELECT date_trunc ('month', time) as month,
       action,
       count (order_id) as orders_count
FROM   user_actions
GROUP BY month, action
ORDER BY month, action;

--5
--По данным в таблице users посчитайте максимальный порядковый номер месяца среди всех порядковых номеров месяцев рождения пользователей сервиса. С помощью группировки проведите расчёты отдельно в двух группах — для пользователей мужского и женского пола.
--Новую колонку с максимальным номером месяца рождения в группах назовите max_month. Преобразуйте значения в новой колонке в формат INTEGER, чтобы порядковый номер был выражен целым числом.
--Результат отсортируйте по колонке с полом пользователей.

SELECT sex,
       max(date_part('month', birth_date))::integer as max_month
FROM   users
GROUP BY sex
ORDER BY sex;

--6
--По данным в таблице users посчитайте порядковый номер месяца рождения самого молодого пользователя сервиса.
--С помощью группировки проведите расчёты отдельно в двух группах — для пользователей мужского и женского пола.
--Новую колонку с максимальным номером месяца рождения в группах назовите max_month.
--Преобразуйте значения в новой колонке в формат INTEGER, чтобы порядковый номер был выражен целым числом.
--Результат отсортируйте по колонке с полом пользователей.

SELECT sex,
       date_part('month', max(birth_date))::integer as max_month
FROM   users
GROUP BY sex
ORDER BY sex;

--7
--Посчитайте максимальный возраст пользователей мужского и женского пола в таблице users. Возраст измерьте числом полных лет.
--Новую колонку с возрастом назовите max_age. Преобразуйте значения в новой колонке в формат INTEGER, чтобы возраст был выражен целым числом.
--Результат отсортируйте по новой колонке по возрастанию возраста.

SELECT sex,
       max(date_part('year', age(current_date, birth_date)))::integer as max_age
FROM   users
GROUP BY sex
ORDER BY max_age;

--8
--Разбейте пользователей из таблицы users на группы по возрасту (возраст по-прежнему измеряем числом полных лет) и посчитайте количество пользователей каждого возраста.
--Колонку с возрастом назовите age, а колонку с числом пользователей — users_count.
--Преобразуйте значения в колонке с возрастом в формат INTEGER, чтобы возраст был выражен целым числом.
--Результат отсортируйте по колонке с возрастом по возрастанию.

SELECT date_part('year', age(current_date, birth_date))::integer as age,
       count (user_id) as users_count
FROM   users
GROUP BY age
ORDER BY age;

--9
--Вновь разбейте пользователей из таблицы users на группы по возрасту (возраст по-прежнему измеряем количеством полных лет), только теперь добавьте в группировку ещё и пол пользователя. Затем посчитайте количество пользователей в каждой половозрастной группе.
--Все NULL значения в колонке birth_date заранее отфильтруйте с помощью WHERE.
--Колонку с возрастом назовите age, а колонку с числом пользователей — users_count, имя колонки с полом оставьте без изменений. Преобразуйте значения в колонке с возрастом в формат INTEGER, чтобы возраст был выражен целым числом.
--Отсортируйте полученную таблицу сначала по колонке с возрастом по возрастанию, затем по колонке с полом — тоже по возрастанию.

SELECT date_part('year', age(current_date, birth_date))::integer as age,
       sex,
       count (user_id) as users_count
FROM   users
WHERE  birth_date is not null
GROUP BY age, sex
ORDER BY age, sex;

--10
--Посчитайте количество товаров в каждом заказе, примените к этим значениям группировку и рассчитайте количество заказов в каждой группе за неделю с 29 августа по 4 сентября 2022 года включительно. Для расчётов используйте данные из таблицы orders.
--Выведите две колонки: размер заказа и число заказов такого размера за указанный период. Колонки назовите соответственно order_size и orders_count.
--Результат отсортируйте по возрастанию размера заказа.

SELECT array_length(product_ids, 1) as order_size,
       count (order_id) as orders_count
FROM   orders
WHERE  creation_time between '2022-08-29'
   and '2022-09-04 23:59:59'
GROUP BY order_size
ORDER BY order_size;

--11
--Посчитайте количество товаров в каждом заказе, примените к этим значениям группировку и рассчитайте количество заказов в каждой группе. Учитывайте только заказы, оформленные по будням. В результат включите только те размеры заказов, общее число которых превышает 2000. Для расчётов используйте данные из таблицы orders.
--Выведите две колонки: размер заказа и число заказов такого размера. Колонки назовите соответственно order_size и orders_count.
--Результат отсортируйте по возрастанию размера заказа.

SELECT array_length(product_ids, 1) as order_size,
       count (order_id) as orders_count
FROM   orders
WHERE  date_part ('dow', creation_time) in (1, 2, 3, 4, 5)
GROUP BY order_size having count (order_id) > 2000
ORDER BY order_size;

--12
--По данным из таблицы user_actions определите пять пользователей, сделавших в августе 2022 года наибольшее количество заказов.
--Выведите две колонки — id пользователей и число оформленных ими заказов. Колонку с числом оформленных заказов назовите created_orders.
--Результат отсортируйте сначала по убыванию числа заказов, сделанных пятью пользователями, затем по возрастанию id этих пользователей.

SELECT user_id,
       count (order_id) as created_orders
FROM   user_actions
WHERE  action = 'create_order'
   and time between '2022-08-01 00:00:00'
   and '2022-08-31 23:59:59'
GROUP BY user_id
ORDER BY created_orders desc, user_id limit 5;

--13
--А теперь по данным таблицы courier_actions определите курьеров, которые в сентябре 2022 года доставили только по одному заказу.
--В этот раз выведите всего одну колонку с id курьеров. Колонку с числом заказов в результат включать не нужно.
--Результат отсортируйте по возрастанию id курьера.

SELECT courier_id
FROM   courier_actions
WHERE  action = 'deliver_order'
   and time between '2022-09-01'
   and '2022-09-30 23:59:59'
GROUP BY courier_id having count (order_id) = 1
ORDER BY courier_id;

--14
--Из таблицы user_actions отберите пользователей, у которых последний заказ был создан до 8 сентября 2022 года.
--Выведите только их id, дату создания заказа выводить не нужно.
--Результат отсортируйте по возрастанию id пользователя.

SELECT user_id
FROM   user_actions
WHERE  action = 'create_order'
GROUP BY user_id having max (time) < '2022-09-08'
ORDER BY user_id;

--15
--Разбейте заказы из таблицы orders на 3 группы в зависимости от количества товаров, попавших в заказ:
--Малый (от 1 до 3 товаров);
--Средний (от 4 до 6 товаров);
--Большой (7 и более товаров).
--Посчитайте число заказов, попавших в каждую группу. Группы назовите соответственно «Малый», «Средний», «Большой» (без кавычек).
--Выведите наименования групп и число товаров в них. Колонку с наименованием групп назовите order_size, а колонку с числом заказов — orders_count.
--Отсортируйте полученную таблицу по колонке с числом заказов по возрастанию.

SELECT case when array_length(product_ids, 1) >= 1 and
                 array_length(product_ids, 1) <= 3 then 'Малый'
            when array_length(product_ids, 1) >= 4 and
                 array_length(product_ids, 1) <= 6 then 'Средний'
            else 'Большой' end as order_size,
       count (distinct order_id) as orders_count
FROM   orders
GROUP BY order_size
ORDER BY orders_count;

--16
--Разбейте пользователей из таблицы users на 4 возрастные группы:
--от 18 до 24 лет;
--от 25 до 29 лет;
--от 30 до 35 лет;
--старше 36.
--Посчитайте число пользователей, попавших в каждую возрастную группу. Группы назовите соответственно «18-24», «25-29», «30-35», «36+» (без кавычек).
--В расчётах не учитывайте пользователей, у которых не указана дата рождения.
--Как и в прошлых задачах, в качестве возраста учитывайте число полных лет.
--Выведите наименования групп и число пользователей в них.
--Колонку с наименованием групп назовите group_age, а колонку с числом пользователей — users_count.
--Отсортируйте полученную таблицу по колонке с наименованием групп по возрастанию.

SELECT case when date_part('year', age (birth_date)) >= 36 then '36+'
            when date_part('year', age (birth_date)) >= 30 then '30-35'
            when date_part('year', age (birth_date)) >= 25 then '25-29'
            else '18-24' end as group_age,
       count (distinct user_id) as users_count
FROM   users
WHERE  birth_date is not null
GROUP BY group_age
ORDER BY group_age;

--Вариант верного решения:

SELECT case when date_part('year', age(birth_date)) between 18 and
                 24 then '18-24'
            when date_part('year', age(birth_date)) between 25 and
                 29 then '25-29'
            when date_part('year', age(birth_date)) between 30 and
                 35 then '30-35'
            when date_part('year', age(birth_date)) >= 36 then '36+' end as group_age,
       count(user_id) as users_count
FROM   users
WHERE  birth_date is not null
GROUP BY group_age
ORDER BY group_age;

--17
--По данным из таблицы orders рассчитайте средний размер заказа по выходным и будням.
--Группу с выходными днями (суббота и воскресенье) назовите «weekend», а группу с будними днями (с понедельника по пятницу) — «weekdays» (без кавычек).
--В результат включите две колонки: колонку с группами назовите week_part, а колонку со средним размером заказа — avg_order_size. 
--Средний размер заказа округлите до двух знаков после запятой.
--Результат отсортируйте по колонке со средним размером заказа — по возрастанию.

SELECT case when date_part ('dow', creation_time) in (1, 2, 3, 4, 5) then 'weekdays'
            else 'weekend' end as week_part,
       round (avg (array_length(product_ids, 1)), 2) as avg_order_size
FROM   orders
GROUP BY week_part
ORDER BY avg_order_size;

--18
--Для каждого пользователя в таблице user_actions посчитайте общее количество оформленных заказов и долю отменённых заказов.
--Новые колонки назовите соответственно orders_count и cancel_rate. Колонку с долей отменённых заказов округлите до двух знаков после запятой.
--В результат включите только тех пользователей, которые оформили больше трёх заказов и у которых показатель cancel_rate составляет не менее 0.5.
--Результат отсортируйте по возрастанию id пользователя.

SELECT user_id,
       count (distinct order_id) filter (WHERE action = 'create_order') as orders_count,
       round (count (distinct order_id) filter (WHERE action = 'cancel_order')/count (distinct order_id)::decimal, 2) as cancel_rate
FROM   user_actions
GROUP BY user_id having count (distinct order_id) filter (
WHERE  action = 'create_order') > 3
   and round (count (distinct order_id) filter (
WHERE  action = 'cancel_order')/count (distinct order_id)::decimal, 2) >= 0.5
ORDER BY user_id;

--Вариант верного решения:

SELECT user_id,
       round(count(distinct order_id) filter (WHERE action = 'cancel_order')::decimal / count(distinct order_id),
             2) as cancel_rate,
       count(distinct order_id) as orders_count
FROM   user_actions
GROUP BY user_id having round(count(distinct order_id) filter (
WHERE  action = 'cancel_order')::decimal / count(distinct order_id), 2) >= 0.5
   and count(distinct order_id) > 3
ORDER BY user_id

--19
--Для каждого дня недели в таблице user_actions посчитайте:
--Общее количество оформленных заказов.
--Общее количество отменённых заказов.
--Общее количество неотменённых заказов (т.е. доставленных).
--Долю неотменённых заказов в общем числе заказов (success rate).
--Новые колонки назовите соответственно created_orders, canceled_orders, actual_orders и success_rate. Колонку с долей неотменённых заказов округлите до трёх знаков после запятой.
--Все расчёты проводите за период с 24 августа по 6 сентября 2022 года включительно, чтобы во временной интервал попало равное количество разных дней недели.
--Группы сформируйте следующим образом: выделите день недели из даты с помощью функции to_char с параметром 'Dy', также выделите порядковый номер дня недели с помощью функции DATE_PART с параметром 'isodow'. Далее сгруппируйте данные по двум полям и проведите все необходимые расчёты.
--В результате должна получиться группировка по двум колонкам: с порядковым номером дней недели и их сокращёнными наименованиями.
--Результат отсортируйте по возрастанию порядкового номера дня недели.

SELECT date_part ('isodow', time)::integer as weekday_number,
       to_char (time, 'Dy') as weekday,
       count (distinct order_id) filter (WHERE action = 'create_order') as created_orders,
       count (distinct order_id) filter (WHERE action = 'cancel_order') as canceled_orders,
       count(distinct order_id) filter (WHERE action = 'create_order') - count(distinct order_id) filter (WHERE action = 'cancel_order') as actual_orders,
       round((count(distinct order_id) filter (WHERE action = 'create_order') - count(distinct order_id) filter (WHERE action = 'cancel_order'))::decimal / count(distinct order_id) filter (WHERE action = 'create_order'),
             3) as success_rate
FROM   user_actions
WHERE  time between '2022-08-24'
   and '2022-09-06 23:59:59'
GROUP BY weekday_number, weekday
ORDER BY weekday_number;

Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: