Почему запрос 1С не выводит строки с нулевым значением и как это исправить?

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

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

Анализ исходной проблемы

Проанализируем типовой запрос, с которым сталкиваются разработчики. Задача заключается в том, чтобы вывести список номенклатуры и контрагентов, а также рассчитать просрочку в рабочих днях по регистру сведений ДанныеПроизводственногоКалендаря. Если просрочки нет, строка все равно должна присутствовать в итоговом отчете с нулевым значением или соответствующей отметкой.

Посмотрим на ошибочный фрагмент запроса:


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

Выясним причину, почему такой запрос отсекает непросроченные позиции. Перечисление таблиц через запятую в секции ИЗ создает неявное соединение (декартово произведение). Когда условия отбора по второй таблице (например, проверка попадания даты в интервал МЕЖДУ) помещаются в секцию ГДЕ, такое соединение работает как внутреннее (ВНУТРЕННЕЕ СОЕДИНЕНИЕ). Если в регистре календаря нет записей за указанный период, результатом связи становится пустой набор данных, и вся запись из ИтоговаяТаблица полностью отбрасывается.

Решение проблемы: перевод на левое соединение с произвольным условием

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

  1. Заменим перечисление таблиц через запятую на явное ЛЕВОЕ СОЕДИНЕНИЕ.
  2. Перенесем все условия, касающиеся правой таблицы (производственного календаря), из секции ГДЕ в секцию условия связи ПО.
  3. Условия, относящиеся исключительно к левой таблице (например, ИтоговаяТаблица.ПоФакту < ИтоговаяТаблица.ПоДоговору), оставим в секции ГДЕ или переместим в условия соединения в зависимости от бизнес-логики.

В конструкторе запросов 1С для добавления такого условия переходят на вкладку «Связи», выбирают обе таблицы, устанавливают флаг «Произвольное» и прописывают условие связи вручную.

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


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

Особенности работы агрегатных функций и типов данных

Обратим внимание на важные детали при работе с левым соединением и функцией КОЛИЧЕСТВО в языке запросов 1С:

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

2. Избегайте смешивания типов данных. Не рекомендуется использовать конструкции вида:


ВЫБОР 
	КОГДА КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ДанныеПроизводственногоКалендаря.Дата) > 0 
		ТОГДА КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ДанныеПроизводственногоКалендаря.Дата) 
	ИНАЧЕ "нет" 
КОНЕЦ КАК ПросрочкаВРабочихДнях

Возврат строки "нет" вместо числа 0 создает составной тип поля (число + строка). Это делает невозможным подведение итогов, наложение стандартных числовых форматов и вызов арифметических функций в Системе компоновки данных (СКД). Оставляйте числовое значение 0, а текстовое представление при необходимости настраивайте в условном оформлении отчета.

3. Нормализация дат и времени. Для корректной работы оператора МЕЖДУ убедитесь, что реквизиты дат приведены к началу дня с помощью функции НАЧАЛОПЕРИОДА(Дата, ДЕНЬ) или к концу дня с помощью КОНЕЦПЕРИОДА(Дата, ДЕНЬ). Если дата начала содержит время (например, 14:30:00), записи производственного календаря за это утро могут быть ошибочно исключены из подсчета.

← На главную