0Pricing
Coding Interview Prep · Урок

Накопительное распределение и доля от общего

Рассчитывайте накопительные проценты и долю от общего внутри разделов.

«Накопительное распределение и доля от общего» — бесплатный урок 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 — локальная установка не требуется.

Все уроки этого курса

  1. Накопительные суммы с оконными рамками
  2. Рамки ROWS и RANGE
  3. Скользящие средние в скользящем окне
  4. Накопительное распределение и доля от общего
← Назад к Coding Interview Prep