Как рассчитать процентное отношение двух колонок в запросе 1С с защитой от деления на ноль и корректным форматированием?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке отчетов и обработок в системе 1С:Предприятие одной из наиболее частых задач является расчет относительных показателей, в частности — процентного соотношения двух числовых величин. На первый взгляд задача кажется тривиальной и сводится к школьной формуле деления одного числа на другое с последующим умножением на 100. Однако при работе с реальными базами данных разработчик неизбежно сталкивается с техническими нюансами: наличием пустых значений NULL, риском возникновения критической ошибки деления на ноль и необходимостью красивого округления полученного результата.

В рамках данной статьи мы подробно разберем, как правильно реализовать этот расчет на уровне запроса 1С, как избежать падения системы при делении на ноль, а также рассмотрим профессиональный подход к выводу процентов с использованием возможностей Системы компоновки данных (СКД).

Анализ исходной задачи и математической логики

Представим стандартную ситуацию, описанную автором темы. В результате выполнения запроса мы получаем две числовые колонки (назовем их Колонка1 и Колонка2). Нам требуется получить третью колонку, в которой будет отображаться процентное отношение второй колонки к первой.

Давайте проанализируем исходные данные из примера:

  1. Строка 1: Значение 1 = 1000, Значение 2 = 630. Ожидаемый процент: 63% (расчет: 630 / 1000 * 100 = 63%).
  2. Строка 2: Значение 1 = 1200, Значение 2 = 420. Ожидаемый процент по версии автора темы: 42%.
  3. Строка 3: Значение 1 = 100, Значение 2 = 30. Ожидаемый процент: 30% (расчет: 30 / 100 * 100 = 30%).

Выясним причину несоответствия во второй строке. Автор темы допустил классическую ментальную ошибку из-за невнимательности или усталости. Он интуитивно продолжил делить значение второй строки на фиксированную базу первой строки (1000), посчитав, что там также указана тысяча («думал 1к написал»). При делении 420 на 1000 мы действительно получили бы 42%. Однако реальный расчет для второй строки выглядит следующим образом: 420 / 1200 * 100 = 35%.

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

Проблема деления на ноль и значений NULL в базах данных

Прежде чем писать код запроса, разберем ключевые опасности, подстерегающие разработчика при работе с СУБД (будь то MS SQL Server, PostgreSQL, IBM DB2, Oracle или файловая база данных 1С):

1. Деление на ноль. Если в Колонка1 (знаменатель) окажется значение 0, то любая СУБД мгновенно прервет выполнение запроса и вернет критическую ошибку выполнения (Division by zero). Это приведет к аварийному завершению работы отчета у пользователя.

2. Значения NULL. Если данные выбираются из левого или полного соединения таблиц, в полях неизбежно будут появляться незаполненные значения NULL. Любая арифметическая операция с участием NULL (например, NULL / 5 или 100 * NULL) в результате всегда дает NULL. Хотя это не вызывает аварийного завершения запроса, на выходе мы получим пустые ячейки в отчете, что выглядит некрасиво и затрудняет дальнейший анализ.

Решение 1: Безопасный расчет процента непосредственно в тексте запроса 1С

Рассмотрим подробнее, как реализовать расчет непосредственно на языке запросов 1С. Для того чтобы обойти указанные выше проблемы, нам необходимо использовать комбинацию встроенных функций запроса: ВЫБОР, ЕСТЬNULL и ВЫРАЗИТЬ.

Посмотрим на пример безопасного построения запроса:


ВЫБРАТЬ
    ИсходныеДанные.Колонка1 КАК к1,
    ИсходныеДанные.Колонка2 КАК к2,
    ВЫБОР
        КОГДА ЕСТЬNULL(ИсходныеДанные.Колонка1, 0) = 0
            ТОГДА 0
        ИНАЧЕ ВЫРАЗИТЬ(ЕСТЬNULL(ИсходныеДанные.Колонка2, 0) / ИсходныеДанные.Колонка1 * 100 КАК ЧИСЛО(15, 2))
    КОНЕЦ КАК ПроцентноеОтношение
ИЗ
    &ТаблицаИсточника КАК ИсходныеДанные

Разберем этот программный код по шагам, чтобы понять логику его работы:

  1. Конструкция ВЫБОР...КОГДА...ТОГДА...ИНАЧЕ...КОНЕЦ представляет собой аналог условного оператора в языках программирования. Она позволяет СУБД проверять условия последовательно.
  2. Функция ЕСТЬNULL(ИсходныеДанные.Колонка1, 0) проверяет значение в первой колонке. Если там содержится NULL, функция заменяет его на числовой ноль. Если там уже содержится число (включая реальный 0), оно остается без изменений.
  3. Первое условие КОГДА ЕСТЬNULL(ИсходныеДанные.Колонка1, 0) = 0 проверяет, не равен ли наш знаменатель нулю (или NULL, который мы предварительно превратили в ноль). Если это условие выполняется, система сразу же возвращает результат 0 в качестве процента, минуя математическую операцию деления. Тем самым мы гарантируем абсолютную защиту от ошибки деления на ноль.
  4. В ветке ИНАЧЕ происходит непосредственный расчет. Мы берем значение числителя ЕСТЬNULL(ИсходныеДанные.Колонка2, 0), делим на значение знаменателя Колонка1 (в этой ветке мы уже на 100% уверены, что знаменатель не равен нулю) и умножаем на 100 для получения процентного значения.
  5. Функция ВЫРАЗИТЬ(... КАК ЧИСЛО(15, 2)) используется для приведения типа результата. При делении чисел в базах данных часто получаются бесконечные периодические дроби или числа с огромным количеством знаков после запятой (например, 33.33333333333...). С помощью этой функции мы жестко округляем результат до двух знаков после запятой, что делает вывод данных эстетичным и читаемым для пользователя.

Решение 2: Профессиональный подход с использованием возможностей СКД

Хотя расчет процентов внутри запроса (как описано в Решении 1) является абсолютно рабочим и часто применяется на практике, опытные разработчики предпочитают использовать другой, более гибкий и архитектурно правильный подход при разработке отчетов на СКД (Системе компоновки данных).

Проанализируем ситуацию: почему рассчитывать проценты (умножая на 100) прямо в запросе не всегда полезно? Дело в том, что если мы получим готовые проценты в запросе, то при расчете общих итогов по группировкам (например, по иерархии номенклатуры или по контрагентам) СКД попытается просто сложить эти проценты или рассчитать их среднее арифметическое. С точки зрения математики, сумма процентов или среднее значение от процентов по разным строкам — это грубейшая ошибка. Итоговый процент должен рассчитываться заново как отношение суммы всех числителей к сумме всех знаменателей.

Поэтому правильный подход заключается в следующем: в самом запросе мы рассчитываем только «чистый» коэффициент отношения (без умножения на 100), а форматирование и отображение в виде процентов перекладываем на уровень представления СКД.

Разберем этот метод по шагам:

Шаг 1. В запросе СКД пишем расчет коэффициента:


ВЫБРАТЬ
    ИсходныеДанные.Колонка1 КАК к1,
    ИсходныеДанные.Колонка2 КАК к2,
    ВЫБОР
        КОГДА ЕСТЬNULL(ИсходныеДанные.Колонка1, 0) = 0
            ТОГДА 0
        ИНАЧЕ ИсходныеДанные.Колонка2 / ИсходныеДанные.Колонка1
    КОНЕЦ КАК КоэффициентОтношения
ИЗ
    &ТаблицаИсточника КАК ИсходныеДанные

Обратите внимание: мы не умножаем результат на 100. Для строки с исходными данными 1000 и 630 результатом будет число 0.63, а для строки 1200 и 420 — число 0.35.

Шаг 2. Переходим на вкладку «Наборы данных» в конструкторе схемы компоновки данных. Находим наше поле КоэффициентОтношения.

Шаг 3. В колонке «Оформление» для данного поля нажимаем на кнопку выбора. В открывшемся окне параметров оформления находим свойство «Формат».

Шаг 4. В окне конструктора форматной строки настраиваем следующие параметры:

В результате сформированная форматная строка будет выглядеть так:

ЧДЦ=2; ЧС=100; ЧФ='#'%

При таком подходе СКД сама умножит значение 0.35 на 100, округлит до двух знаков после запятой и выведет на экран красивое значение 35,00 %. При этом в итогах по группировкам отчета СКД сможет корректно рассчитать процент, если в поле «Ресурсы» мы укажем правильную формулу расчета общего итога:

СУММА(к2) / ВЫБОР КОГДА СУММА(к1) = 0 ТОГДА 1 ИНАЧЕ СУММА(к1) КОНЕЦ

Культурный контекст: юмор разработчиков (Петерсон и Мордкович)

В оригинальном обсуждении на форуме участники не упустили возможность поиронизировать над математической опечаткой автора, упомянув известные фамилии авторов школьных учебников. Для понимания атмосферы профессионального сообщества разберем этот контекст:

Ирония коллег помогла автору темы быстро осознать свою ошибку, совершенную из-за банального переутомления после выходных дней. Это лишний раз доказывает пользу здорового отдыха для сохранения концентрации внимания при написании программного кода.

Резюме лучших практик

Подводя итоги, сформулируем основные правила, которыми должен руководствоваться разработчик 1С при выводе процентных показателей в отчетах:

  1. Всегда защищайте знаменатель от нулевого значения с помощью конструкции ВЫБОР.
  2. Используйте ЕСТЬNULL для замены неопределенных значений базы данных на числовые нули во избежание пустых полей в отчетах.
  3. Если вы делаете простой реестр или вывод данных без иерархических группировок, рассчитывайте процент прямо в запросе с помощью округления ВЫРАЗИТЬ.
  4. Если вы разрабатываете сложный многоуровневый отчет в СКД, рассчитывайте в запросе чистый коэффициент (деление без умножения на 100), а визуальное отображение процентов настраивайте через свойства формата поля СКД.
← На главную