Накопительное распределение и доля от общего
Рассчитывайте накопительные проценты и долю от общего внутри разделов.
«Накопительное распределение и доля от общего» — бесплатный урок Coding Interview Prep на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Coding Interview Prep, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Coding Interview Prep содержит 4 уроков всего.
Вопрос о доле от общего итога
Типичный вопрос на собеседовании по отчётности: «Какой процент общей выручки приходится на каждую категорию?» и его накопительный вариант: «Какова текущая доля от общего итога?»
Суть в том, чтобы разделить значение каждой строки на оконный агрегат, вычисленный по всему разделу. Важно знать, что общий итог можно поместить в оконную функцию без соединения таблицы с самой собой.
Оконный SUM без ORDER BY = общий итог
Вот ключевой приём: SUM(amount) OVER () с пустым OVER и без ORDER BY возвращает итог всего набора результатов, повторяя его в каждой строке.
Поскольку ORDER BY отсутствует, накопительной рамки нет, поэтому рамка по умолчанию охватывает весь раздел. Итог, повторённый в каждой строке, — именно тот знаменатель, который нужен для вычисления доли от общего итога.
SELECT
category,
amount,
SUM(amount) OVER () AS grand_total
FROM category_sales;Вычисление доли от общего итога
Разделите значение строки на общий итог, вычисленный оконной функцией, и умножьте результат на 100. Преобразуйте значение в десятичное, чтобы целочисленное деление не округлило результат до нуля.
Этот запрос за один проход заменяет прежний шаблон с подзапросом для получения итога и его соединением со строками детализации. Он короче, быстрее и лучше читается.
SELECT
category,
amount,
ROUND(
100.0 * amount / SUM(amount) OVER (),
2
) AS pct_of_total
FROM category_sales;Ловушка целочисленного деления
Классическая каверзная задача на собеседовании: во многих базах данных выражение amount / total для целочисленных столбцов выполняет целочисленное деление, поэтому результат меньше 1 превращается в 0.
Исправьте это, сначала умножив значение на 100.0 (числовой литерал), или преобразовав один из операндов: amount::numeric / total. Если забыть об этом, получится столбец из нулей, что интервьюер заметит мгновенно.
SELECT
category,
amount * 1.0 / SUM(amount) OVER () AS share,
CAST(amount AS DECIMAL) / SUM(amount) OVER () AS share_alt
FROM category_sales;Доля от общего итога внутри группы
Добавьте PARTITION BY, чтобы доля каждой строки рассчитывалась относительно её группы, а не всей таблицы. Например, процент продаж каждого товара от продаж в его регионе.
Знаменатель SUM(amount) OVER (PARTITION BY region) теперь сбрасывается для каждого региона, поэтому проценты внутри каждого региона в сумме дают 100.
SELECT
region,
product,
amount,
ROUND(
100.0 * amount / SUM(amount) OVER (PARTITION BY region),
2
) AS pct_of_region
FROM regional_sales;Текущая доля от общего итога
Объедините накопительный числитель с фиксированным знаменателем, чтобы получить текущую долю от общего итога: какая часть общего итога накопилась к каждой строке.
В числителе используется ORDER BY (накопление), а в знаменателе — пустое OVER () (общий итог). Последняя строка всегда достигает 100%.
SELECT
sale_date,
amount,
ROUND(
100.0 * SUM(amount) OVER (ORDER BY sale_date)
/ SUM(amount) OVER (),
2
) AS running_pct
FROM daily_sales;CUME_DIST: накопительное распределение
В SQL есть встроенная функция для накопительного распределения: CUME_DIST(). Она возвращает долю строк, значение ORDER BY которых меньше либо равно значению текущей строки; результат находится в диапазоне (0, 1].
В отличие от вручную вычисленной текущей доли суммы, CUME_DIST описывает позицию строки и отвечает на вопрос «какая доля строк имеет значение, не превышающее это?». Это полезно для отчётности в стиле процентилей.
SELECT
score,
CUME_DIST() OVER (ORDER BY score) AS cume_dist
FROM exam_results;PERCENT_RANK и его отличие
Близкая функция — PERCENT_RANK(), определяемая как (rank - 1) / (total_rows - 1) и возвращающая значение от 0 до 1.
Различие, которое важно на собеседовании: CUME_DIST включает текущую строку в числитель («на этом уровне или ниже»), тогда как PERCENT_RANK вычисляет относительный ранг, начиная с 0 для первой строки. Функции дают разные значения, и часто их путают.
SELECT
score,
CUME_DIST() OVER (ORDER BY score) AS cd,
PERCENT_RANK() OVER (ORDER BY score) AS pr
FROM exam_results;Анализ Парето / 80–20
Текущая доля от общего итога лежит в основе анализа Парето: «какие клиенты с наибольшими покупками формируют 80% выручки?». Отсортируйте данные по сумме в убывающем порядке, вычислите текущую долю, а затем отфильтруйте строки, в которых накопительная доля впервые пересекает порог 80%.
Поскольку результаты оконных функций нельзя использовать в WHERE, заключите вычисление в CTE и выполните фильтрацию во внешнем запросе — это то же правило, что действует для любой оконной функции.
WITH ranked AS (
SELECT
customer_id,
revenue,
SUM(revenue) OVER (ORDER BY revenue DESC)
/ SUM(revenue) OVER () AS running_share
FROM customer_revenue
)
SELECT *
FROM ranked
WHERE running_share <= 0.80;Округление и согласование итогов
Будьте внимательны: округление каждого процента до 2 знаков после запятой может привести к тому, что сумма в столбце составит 99.99 или 100.01 вместо ровно 100. На собеседовании могут спросить, как гарантировать, что сумма частей равна целому.
Распространённые ответы: округлять только при отображении, хранить полную точность для вычислений или применить к одной строке корректировку по методу наибольших остатков. Важно назвать проблему — это важнее конкретного способа её исправления.
Ключевые тезисы для собеседования
Основные выводы, которые следует уметь сформулировать:
SUM(x) OVER ()без ORDER BY возвращает общий итог в каждой строке.- Умножайте на
100.0, чтобы избежать целочисленного деления. PARTITION BYиспользуется для вычисления долей внутри каждой группы.- Накопительный числитель, поделённый на знаменатель — общий итог, даёт накапливаемую долю.
- Используйте
CUME_DISTиPERCENT_RANKдля анализа распределения и знайте, чем они отличаются. - Оберните запрос в CTE для фильтрации по Парето или порогу.
Быстрая проверка
Как получить общий итог всего набора результатов в каждой строке?
Итоги: распределение и доля от общего итога
Доля от общего итога вычисляется делением значения строки на SUM(x) OVER () — общий итог, возвращаемый в каждой строке; всегда умножайте на 100.0, чтобы избежать целочисленного деления, и добавляйте PARTITION BY для вычисления долей внутри групп. Накопительный числитель, поделённый на общий итог, даёт накапливаемую долю, которая достигает 100% и служит основой анализа Парето.
Для распределения по позициям используйте CUME_DIST и PERCENT_RANK и помните об ограничении, связанном с округлением и согласованием итогов. На этом изучение накопительных итогов и скользящих средних завершено.
Часто задаваемые вопросы
Урок «Накопительное распределение и доля от общего» бесплатный?
Да — полный текст урока «Накопительное распределение и доля от общего» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Coding Interview Prep, подпишись на CoddyKit PRO. Курс Coding Interview Prep содержит 4 уроков всего.
Чему я научусь в уроке «Накопительное распределение и доля от общего»?
Рассчитывайте накопительные проценты и долю от общего внутри разделов. Ты практикуешь Coding Interview Prep с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Coding Interview Prep?
Предыдущий опыт не требуется. Coding Interview Prep на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Накопительное распределение и доля от общего»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Coding Interview Prep?
Да. Каждый урок Coding Interview Prep включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Накопительные суммы с оконными рамками
- Рамки ROWS и RANGE
- Скользящие средние в скользящем окне
- Накопительное распределение и доля от общего