Почему запрос к регистру "Страховые взносы исчисленные" возвращает пустых сотрудников?

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

При разработке отчетов по расчету страховых взносов в программах "1С:Зарплата и управление персоналом" или "1С:ERP" разработчики часто сталкиваются с задачей получения списка сотрудников, за которых уплачивались дополнительные взносы за вредные или тяжелые условия труда. Однако стандартный запрос к регистру накопления СтраховыеВзносыИсчисленные может преподнести сюрприз: вместо ожидаемых имен сотрудников в результате запроса выводятся пустые строки.

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

Разбор исходной проблемы: почему вместо сотрудников выводятся пустые строки?

Рассмотрим ситуацию на примере запроса, который часто пытаются написать начинающие разработчики:


ВЫБРАТЬ
    СтраховыеВзносыИсчисленные.Период,
    ВЫБОР
        КОГДА СУММА(СтраховыеВзносыИсчисленные.ПФРЗаЗанятыхНаПодземныхИВредныхРаботахВредный2) > 0
            ТОГДА СтраховыеВзносыИсчисленные.ФизЛицо.Наименование
        ИНАЧЕ ""
    КОНЕЦ КАК Сотрудник
ИЗ
    РегистрНакопления.СтраховыеВзносыИсчисленные КАК СтраховыеВзносыИсчисленные
ГДЕ
    СтраховыеВзносыИсчисленные.ДатаПолученияДохода МЕЖДУ &НачалоПериода И &КонецПериода
СГРУППИРОВАТЬ ПО
    СтраховыеВзносыИсчисленные.Период,
    СтраховыеВзносыИсчисленные.ФизЛицо.Наименование

При выполнении такого запроса для периодов, где заведомо должны быть сотрудники-вредники, колонка "Сотрудник" остается абсолютно пустой. Проанализируем ситуацию и выделим две основные ошибки в этом коде: методическую и архитектурную.

Методическая ошибка: Использование агрегатной функции СУММА() внутри условной конструкции ВЫБОР КОГДА при наличии группировки. Написание подобных конструкций заставляет СУБД выполнять избыточные вычисления. Кроме того, группировка по строковому представлению ФизЛицо.Наименование (обращение через точку к реквизиту справочника) приводит к неявному левому соединению с таблицей физических лиц, что крайне негативно сказывается на производительности СУБД.

Архитектурная ошибка (главная причина пустого результата): Неверно выбранный ресурс регистра. Автор запроса проверяет только одно конкретное поле — ПФРЗаЗанятыхНаПодземныхИВредныхРаботахВредный2. Если в вашей организации по результатам специальной оценки условий труда (СОУТ) сотрудникам установлен иной класс вредности (например, "Вредный 1", "Вредный 3" или спецоценка вообще не проводилась), то в выбранной колонке гарантированно будут нулевые значения. В результате условие ВЫБОР КОГДА всегда возвращает ветку ИНАЧЕ "".

Сложная структура регистра "Страховые взносы исчисленные"

Выясним причину, почему в полях этого регистра так легко запутаться. Дело в том, что учет дополнительных тарифов за вредность в 1С реализован с высокой степенью детализации. Ресурсы регистра делятся по двум ключевым признакам:

  1. По спискам профессий (классические вредные условия):
    • Список № 1 (подземные работы, работы с вредными условиями труда): имена ресурсов начинаются с префикса ПФРЗаЗанятыхНаПодземныхИВредныхРаботах...
    • Список № 2 (работы с тяжелыми условиями труда и прочие): имена ресурсов начинаются с префикса ПФРЗаЗанятыхНаТяжелыхИПрочихРаботах...
  2. По результатам специальной оценки условий труда (СОУТ):
    • Если СОУТ не проводилась, взносы начисляются по базовому тарифу и записываются в ресурсы с окончанием ...БезСпецОценки или в базовые ресурсы общего характера.
    • Если СОУТ была проведена, ресурсы жестко разделяются по классам и подклассам условий труда:
      • Класс 4 (Опасный): ресурс оканчивается на ...Опасный
      • Класс 3.4 (Вредный 4): ресурс оканчивается на ...Вредный4
      • Класс 3.3 (Вредный 3): ресурс оканчивается на ...Вредный3
      • Класс 3.2 (Вредный 2): ресурс оканчивается на ...Вредный2 (именно его ошибочно выбрал автор)
      • Класс 3.1 (Вредный 1): ресурс оканчивается на ...Вредный1

Таким образом, если вы проверяете только одно поле, вы упускаете из виду сотрудников, у которых в кадровых документах или результатах СОУТ указан другой подкласс вредности.

Решение №1: Использование конструкции ИМЕЮЩИЕ

Для того чтобы исправить логику запроса и уйти от неоптимальной конструкции ВЫБОР КОГДА в полях выборки, мы должны использовать секцию ИМЕЮЩИЕ (аналог HAVING в SQL). Это позволит отсечь строки с нулевыми суммами еще на этапе группировки СУБД.

Рассмотрим пример исправленного запроса, ориентированного на конкретный вид взносов:


ВЫБРАТЬ
    СтраховыеВзносыИсчисленные.Период КАК Период,
    СтраховыеВзносыИсчисленные.ФизЛицо КАК ФизЛицо
ИЗ
    РегистрНакопления.СтраховыеВзносыИсчисленные КАК СтраховыеВзносыИсчисленные
ГДЕ
    СтраховыеВзносыИсчисленные.ДатаПолученияДохода МЕЖДУ &НачалоПериода И &КонецПериода
СГРУППИРОВАТЬ ПО
    СтраховыеВзносыИсчисленные.Период,
    СтраховыеВзносыИсчисленные.ФизЛицо
ИМЕЮЩИЕ
    СУММА(СтраховыеВзносыИсчисленные.ПФРЗаЗанятыхНаПодземныхИВредныхРаботахВредный2) > 0

В данном случае мы группируем данные по ссылочному полю ФизЛицо, а фильтрацию осуществляем в секции ИМЕЮЩИЕ. Если по выбранному ресурсу сумма взносов за период окажется нулевой, строка просто не попадет в итоговую выборку.

Решение №2: Создание универсального и быстрого запроса

Если наша задача — гарантированно и без ошибок получить список всех "вредников" компании за период, мы не имеем права завязываться на какой-то один конкретный подкласс условий труда. Нам необходимо суммировать абсолютно все возможные доп. тарифы, которые могут быть начислены сотрудникам.

Разберем по шагам создание оптимального и надежного запроса с использованием временной таблицы (ВТ). Это лучший подход с точки зрения производительности и качества кода.

Шаг 1. Создание временной таблицы с группировкой и фильтрацией по ссылкам.

Сначала мы выберем данные из регистра, просуммируем все возможные поля дополнительных взносов (и по Списку №1, и по Списку №2, включая все классы СОУТ) и сгруппируем их по Период и ссылке ФизЛицо. Отбор строк с нулевыми суммами сделаем через ИМЕЮЩИЕ.


ВЫБРАТЬ
    СтраховыеВзносы.Период КАК Период,
    СтраховыеВзносы.ФизЛицо КАК ФизЛицо,
    СУММА(
        СтраховыеВзносы.ПФРЗаЗанятыхНаПодземныхИВредныхРаботах +
        СтраховыеВзносы.ПФРЗаЗанятыхНаПодземныхИВредныхРаботахБезСпецОценки +
        СтраховыеВзносы.ПФРЗаЗанятыхНаПодземныхИВредныхРаботахВредный1 +
        СтраховыеВзносы.ПФРЗаЗанятыхНаПодземныхИВредныхРаботахВредный2 +
        СтраховыеВзносы.ПФРЗаЗанятыхНаПодземныхИВредныхРаботахВредный3 +
        СтраховыеВзносы.ПФРЗаЗанятыхНаПодземныхИВредныхРаботахВредный4 +
        СтраховыеВзносы.ПФРЗаЗанятыхНаПодземныхИВредныхРаботахОпасный +
        СтраховыеВзносы.ПФРЗаЗанятыхНаТяжелыхИПрочихРаботах +
        СтраховыеВзносы.ПФРЗаЗанятыхНаТяжелыхИПрочихРаботахБезСпецОценки +
        СтраховыеВзносы.ПФРЗаЗанятыхНаТяжелыхИПрочихРаботахВредный1 +
        СтраховыеВзносы.ПФРЗаЗанятыхНаТяжелыхИПрочихРаботахВредный2 +
        СтраховыеВзносы.ПФРЗаЗанятыхНаТяжелыхИПрочихРаботахВредный3 +
        СтраховыеВзносы.ПФРЗаЗанятыхНаТяжелыхИПрочихРаботахВредный4 +
        СтраховыеВзносы.ПФРЗаЗанятыхНаТяжелыхИПрочихРаботахОпасный
    ) КАК СуммаДопВзносов
ПОМЕСТИТЬ ВТ_СотрудникиВредники
ИЗ
    РегистрНакопления.СтраховыеВзносыИсчисленные КАК СтраховыеВзносы
ГДЕ
    СтраховыеВзносы.ДатаПолученияДохода МЕЖДУ &НачалоПериода И &КонецПериода
СГРУППИРОВАТЬ ПО
    СтраховыеВзносы.Период,
    СтраховыеВзносы.ФизЛицо
ИМЕЮЩИЕ
    СУММА(
        СтраховыеВзносы.ПФРЗаЗанятыхНаПодземныхИВредныхРаботах +
        СтраховыеВзносы.ПФРЗаЗанятыхНаПодземныхИВредныхРаботахБезСпецОценки +
        СтраховыеВзносы.ПФРЗаЗанятыхНаПодземныхИВредныхРаботахВредный1 +
        СтраховыеВзносы.ПФРЗаЗанятыхНаПодземныхИВредныхРаботахВредный2 +
        СтраховыеВзносы.ПФРЗаЗанятыхНаПодземныхИВредныхРаботахВредный3 +
        СтраховыеВзносы.ПФРЗаЗанятыхНаПодземныхИВредныхРаботахВредный4 +
        СтраховыеВзносы.ПФРЗаЗанятыхНаПодземныхИВредныхРаботахОпасный +
        СтраховыеВзносы.ПФРЗаЗанятыхНаТяжелыхИПрочихРаботах +
        СтраховыеВзносы.ПФРЗаЗанятыхНаТяжелыхИПрочихРаботахБезСпецОценки +
        СтраховыеВзносы.ПФРЗаЗанятыхНаТяжелыхИПрочихРаботахВредный1 +
        СтраховыеВзносы.ПФРЗаЗанятыхНаТяжелыхИПрочихРаботахВредный2 +
        СтраховыеВзносы.ПФРЗаЗанятыхНаТяжелыхИПрочихРаботахВредный3 +
        СтраховыеВзносы.ПФРЗаЗанятыхНаТяжелыхИПрочихРаботахВредный4 +
        СтраховыеВзносы.ПФРЗаЗанятыхНаТяжелыхИПрочихРаботахОпасный
    ) > 0
;

Шаг 2. Получение строковых представлений из временной таблицы.

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


ВЫБРАТЬ
    ВТ_СотрудникиВредники.Период КАК Период,
    ВТ_СотрудникиВредники.ФизЛицо.Наименование КАК Сотрудник,
    ВТ_СотрудникиВредники.СуммаДопВзносов КАК СуммаДопВзносов
ИЗ
    ВТ_СотрудникиВредники КАК ВТ_СотрудникиВредники
УПОРЯДОЧИТЬ ПО
    Период,
    Сотрудник

Преимущества универсального подхода

Рассмотрим подробнее, почему предложенное решение во втором варианте является наиболее качественным:

Применяйте данные рекомендации на практике, внимательно анализируйте структуру используемых регистров, и ваши отчеты всегда будут работать быстро и возвращать корректные данные!

← На главную