Как правильно обработать пустую временную таблицу в запросе 1С и избежать ошибок соединения

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

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

Анализ проблемы: почему возникает сбой при отсутствии записей

Рассмотрим ситуацию, когда в отчете выполняется группировка расходов из временной таблицы ТаблицаРасходов с использованием ЛЕВОЕ СОЕДИНЕНИЕ по условию ПО (ИСТИНА):


ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
    ТаблицаРасходов.Период КАК Период,
    СУММА(ТаблицаРасходов.СуммаФакт) КАК СуммаРасходов
ИЗ
    ТаблицаРасходов КАК ТаблицаРасходов
СГРУППИРОВАТЬ ПО
    ТаблицаРасходов.Период) КАК ИтоговаяТаблицаРасходов
ПО (ИСТИНА)

Выясним причину, почему данная конструкция ломает расчеты, если временная таблица ТаблицаРасходов не содержит ни одной строки:

  1. Сворачивание пустой таблицы: В языке запросов 1С подзапрос с конструкцией СГРУППИРОВАТЬ ПО и агрегатными функциями по пустой таблице возвращает 0 строк (а не одну строку с нулевыми суммами).
  2. Потеря данных при соединении: Левое соединение с подзапросом, содержащим 0 строк, для всех выбираемых полей правой таблицы возвращает значение NULL. В результате периоды и суммы расходов становятся не определены.
  3. Ошибка опечатки в связи: Если в условии связи указать ПО ИтоговаяТаблицаДоходов.Период = ИтоговаяТаблицаДоходов.Период, таблица связывается сама с собой, из-за чего сопоставление периодов с расходами полностью теряет смысл.

Почему подстановка числа вместо даты в ЕСТЬNULL приводит к ошибкам

Попытка исправить значение периода с помощью функции ЕСТЬNULL(Период, 0) создаст новые проблемы на стороне встроенного языка 1С. Посмотрим, к каким последствиям это приводит:

  1. Ошибка типизации в BSL: Подстановка числа 0 меняет тип поля с даты на составной тип (Дата, Число). При попытке выполнить сравнение в коде: Если СтрокаПериод.Период >= СметаЗатрат.ДатаНачала Тогда платформа генерирует исключение: «Операции допустимы только для примитивных типов (булево, число, дата...)», так как система не может сравнить числовое значение 0 с типом Дата.
  2. Ошибка «Повторяющийся псевдоним»: При динамическом формировании текста запроса суффикс колонки создается с помощью функции формата: ПрефиксПериода = Формат(СтрокаПериод.Период, "ДФ=MMyy"); Если в поле Период находится значение 0 или NULL, функция Формат() возвращает пустую строку. На каждой итерации цикла генерируются одинаковые псевдонимы колонок (например, СуммаФакт вместо СуммаФакт0124), из-за чего запрос завершается с ошибкой повторения имен полей.

Способы решения проблемы

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

Вариант 1. Предварительная проверка наличия данных

Перед выполнением основного запроса проверим, есть ли записи во временной таблице ТаблицаРасходов. Это можно сделать быстрым точечным запросом:


ЗапросПроверки = Новый Запрос;
ЗапросПроверки.МенеджерВременныхТаблиц = МенеджерВТ;
ЗапросПроверки.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1 1 ИЗ ТаблицаРасходов КАК ТаблицаРасходов";

РезультатПроверки = ЗапросПроверки.Выполнить();
Если РезультатПроверки.Пустой() Тогда
    // Заполняем таблицу одной технической записью с нулевой суммой и корректной датой
    // либо меняем логику формирования текста основного запроса
КонецЕсли;

Вариант 2. Объединение доходов и расходов в единую временную таблицу

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

Проанализируем пример такого запроса:


ВЫБРАТЬ
    Доходы.Период КАК Период,
    Доходы.СуммаДоходов КАК СуммаДоходов,
    0 КАК СуммаРасходов
ПОМЕСТИТЬ ВТ_СводныеДанные
ИЗ
    ТаблицаДоходов КАК Доходы

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    Расходы.Период,
    0,
    Расходы.СуммаФакт
ИЗ
    ТаблицаРасходов КАК Расходы
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    Свод.Период КАК Период,
    СУММА(Свод.СуммаДоходов) КАК СуммаДоходов,
    СУММА(Свод.СуммаРасходов) КАК СуммаРасходов
ПОМЕСТИТЬ ВТ_ИтоговыеПоказатели
ИЗ
    ВТ_СводныеДанные КАК Свод
СГРУППИРОВАТЬ ПО
    Свод.Период

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

← На главную