Как вывести суммы из разных таблиц документа и избежать их задваивания

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

В процессе разработки отчетов в системе 1С:Предприятие одной из наиболее часто встречающихся проблем является некорректное суммирование данных при соединении нескольких таблиц. Типичный сценарий: программист пытается объединить данные о начисленной зарплате и удержанном НДФЛ, используя ЛЕВОЕ СОЕДИНЕНИЕ, и обнаруживает, что итоговые суммы увеличились в несколько раз. Давайте разберем, почему это происходит и как правильно решить эту задачу несколькими способами.

Выясняем причину проблемы: почему суммы «плывут»?

Прежде чем переходить к коду, проанализируем ситуацию. Когда мы соединяем две таблицы (например, РегистрНакопления.ОтражениеВБухучетеНачисленнаяЗарплатаИВзносы и РегистрНакопления.ОтражениеВБухучетеНачисленныйНДФЛ) по сотруднику и регистратору, мы ожидаем получить одну строку с общими суммами. Однако в реальности в этих регистрах данные хранятся с разной степенью детализации.

Например, в таблице зарплаты по одному сотруднику может быть три строки (разные виды начислений или подразделения), а в таблице НДФЛ — только одна строка. При использовании ЛЕВОЕ СОЕДИНЕНИЕ система 1С (как и любой SQL-запрос) сопоставит одну строку НДФЛ каждой из трех строк зарплаты. В итоге, если вы просто просуммируете поле СуммаНДФЛ, вы получите значение, увеличенное в три раза. Если же строк много в обеих таблицах, возникает эффект «картезианского произведения», и суммы становятся астрономическими.

Решение №1: Использование временных таблиц и предварительная группировка

Рассмотрим самый надежный способ решения проблемы внутри одного запроса. Основная идея заключается в том, чтобы привести обе таблицы к одинаковой «гранулярности» (детализации) перед тем, как их соединять. Мы должны сгруппировать данные в каждой таблице по ключевым полям соединения (например, ФизическоеЛицо и Регистратор), чтобы на каждую пару «Сотрудник + Документ» приходилась ровно одна строка в каждой временной таблице.

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


// Шаг 1: Подготовка данных по зарплате и взносам
ВЫБРАТЬ
    СУММА(втБухучет.ВзносыПоЕдиномуТарифу + втБухучет.ПФРЗаЗанятыхНаПодземныхИВредныхРаботахСпецОценка + втБухучет.ФССНесчастныеСлучаи) КАК Взносы,
    СУММА(втБухучет.Сумма) КАК СуммаЗарплаты,
    втБухучет.ФизическоеЛицо КАК ФизическоеЛицо,
    втБухучет.Регистратор КАК Регистратор
ПОМЕСТИТЬ ВТ_Зарплата
ИЗ
    РегистрНакопления.ОтражениеВБухучетеНачисленнаяЗарплатаИВзносы КАК втБухучет
ГДЕ
    втБухучет.Регистратор.ПериодРегистрации = НАЧАЛОПЕРИОДА(&ДатаОтчета, МЕСЯЦ)
СГРУППИРОВАТЬ ПО
    втБухучет.ФизическоеЛицо,
    втБухучет.Регистратор;

////////////////////////////////////////////////////////////////////////////////
// Шаг 2: Подготовка данных по НДФЛ
ВЫБРАТЬ
    СУММА(втНДФЛ.Сумма) КАК СуммаНДФЛ,
    втНДФЛ.Регистратор КАК Регистратор,
    втНДФЛ.ФизическоеЛицо КАК ФизическоеЛицо
ПОМЕСТИТЬ ВТ_НДФЛ
ИЗ
    РегистрНакопления.ОтражениеВБухучетеНачисленныйНДФЛ КАК втНДФЛ
СГРУППИРОВАТЬ ПО
    втНДФЛ.Регистратор,
    втНДФЛ.ФизическоеЛицо;

////////////////////////////////////////////////////////////////////////////////
// Шаг 3: Финальное соединение уникальных строк
ВЫБРАТЬ
    Зарплата.Взносы КАК Взносы,
    Зарплата.СуммаЗарплаты КАК Сумма,
    Зарплата.ФизическоеЛицо КАК ФизическоеЛицо,
    Зарплата.Регистратор КАК Регистратор,
    ЕСТЬNULL(НДФЛ.СуммаНДФЛ, 0) КАК СуммаНДФЛ
ИЗ
    ВТ_Зарплата КАК Зарплата
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_НДФЛ КАК НДФЛ
    ПО Зарплата.ФизическоеЛицо = НДФЛ.ФизическоеЛицо
    И Зарплата.Регистратор = НДФЛ.Регистратор

В этом примере мы сначала «схлопнули» все строки по сотруднику в две компактные временные таблицы: ВТ_Зарплата и ВТ_НДФЛ. Теперь, когда мы выполняем ЛЕВОЕ СОЕДИНЕНИЕ, на каждую строку слева гарантированно приходится не более одной строки справа. Это полностью исключает дублирование сумм.

Решение №2: Метод «ОБЪЕДИНИТЬ ВСЕ» (Альтернативный подход)

Если проект сложный и таблиц для соединения очень много (например, нужно добавить еще удержания, пособия и прочее), временные таблицы могут стать громоздкими. В 1С существует более элегантный архитектурный прием — использование конструкции ОБЪЕДИНИТЬ ВСЕ.

Рассмотрим, как это работает: мы выбираем данные из всех источников в одну общую «плоскую» таблицу, а затем группируем результат. Посмотрим на пример:


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

Преимущества этого метода:

  1. Отсутствие соединений (JOIN) делает запрос более производительным на больших объемах данных.
  2. Исключена любая возможность задваивания, так как строки из разных таблиц просто складываются в один список.
  3. Легко добавлять новые регистры — достаточно дописать еще один блок ОБЪЕДИНИТЬ ВСЕ.

Решение №3: Работа в Системе компоновки данных (СКД)

Если вы разрабатываете отчет на базе СКД, то использование сложных запросов с соединениями — это не самый эффективный путь. Система компоновки данных умеет сама корректно объединять данные из разных источников.

Проанализируем шаги для настройки СКД:

  1. Создайте два отдельных набора данных (НаборДанных1 для зарплаты, НаборДанных2 для НДФЛ).
  2. В каждом наборе напишите простой запрос к соответствующему регистру.
  3. Перейдите на закладку Связи наборов данных.
  4. Укажите связь по полям ФизическоеЛицо и Регистратор.

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

Важные рекомендации по работе с регистрами

При работе с регистрами накопления в 1С (особенно в конфигурациях ЗУП, ERP или КА) следует придерживаться нескольких правил:

  1. Используйте виртуальные таблицы: Вместо обращения к физической таблице РегистрНакопления.ОтражениеВБухучете..., старайтесь использовать таблицу Обороты. Она работает значительно быстрее, так как данные в ней уже предварительно агрегированы платформой.
  2. Контролируйте ПериодРегистрации: В запросах к «Отражению в бухучете» всегда важно четко ограничивать период, так как эти таблицы могут быть очень объемными.
  3. Проверяйте роли полей в СКД: Если вы все же используете один запрос, убедитесь, что на закладке «Наборы данных» для полей-ресурсов (суммы) правильно указаны роли, а для измерений (Сотрудник) проставлена роль «Измерение». Это поможет СКД правильно рассчитать агрегаты.

Подводя итог, можно сказать: если вы видите, что суммы в отчете начали умножаться — ищите ЛЕВОЕ СОЕДИНЕНИЕ, в котором правая или левая часть содержит более одной строки на ключ связи. Используйте временные таблицы с группировкой или объединение запросов, и ваши отчеты всегда будут показывать верные цифры.

← На главную