Как отобрать номенклатуру, которой не было в документах поступления за период в 1С?

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

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

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

Выясним причину ошибки: почему фильтр по дате в секции ГДЕ ломает левое соединение

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


ВЫБРАТЬ
	Ном.Ссылка,
	ПоступлениеТоваровУслугТовары.Номенклатура
ИЗ
	Справочник.Номенклатура КАК Ном
		ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПоступлениеТоваровУслуг.Товары КАК ПоступлениеТоваровУслугТовары
		ПО (ПоступлениеТоваровУслугТовары.Номенклатура = Ном.Ссылка)
ГДЕ
	Ном.ЭтоГруппа = ЛОЖЬ
	И ПоступлениеТоваровУслугТовары.Номенклатура ЕСТЬ NULL
	И ПоступлениеТоваровУслугТовары.Ссылка.Дата МЕЖДУ &Дата И &ДатаКон

Разберем по шагам, что происходит при выполнении этого запроса СУБД:

  1. Сначала платформа выполняет ЛЕВОЕ СОЕДИНЕНИЕ таблицы справочника Номенклатура с табличной частью Документ.ПоступлениеТоваровУслуг.Товары. Для позиций номенклатуры, по которым поступлений не было, поля правой таблицы заполняются значениями NULL.
  2. Затем платформа переходит к секции ГДЕ для фильтрации полученной таблицы. Наложение условия ПоступлениеТоваровУслугТовары.Ссылка.Дата МЕЖДУ &Дата И &ДатаКон проверяет дату документа для каждой строки.
  3. Для позиций номенклатуры без поступлений значение ПоступлениеТоваровУслугТовары.Ссылка.Дата равно NULL. Результат сравнения NULL с диапазоном дат всегда дает ЛОЖЬ (неопределенность), поэтому СУБД отсекает абсолютно все строки с NULL.

Таким образом, наложение условия на правую таблицу в секции ГДЕ фактически превращает ЛЕВОЕ СОЕДИНЕНИЕ во ВНУТРЕННЕЕ СОЕДИНЕНИЕ, вычеркивая именно те записи, которые мы пытались отобрать через ЕСТЬ NULL.

Способ 1. Перенос условия по дате в секцию связи (ПО)

Самое простое и быстрое исправление — перенести фильтрацию по дате документа из секции ГДЕ в условие соединения ПО правой таблицы. В этом случае ограничение по периоду применяется до формирования левого соединения, и значения NULL для отсутствующих товаров сохраняются.

Посмотрим на пример правильного запроса:


ВЫБРАТЬ
	Ном.Ссылка КАК Номенклатура
ИЗ
	Справочник.Номенклатура КАК Ном
		ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПоступлениеТоваровУслуг.Товары КАК ПоступлениеТоваровУслугТовары
		ПО (ПоступлениеТоваровУслугТовары.Номенклатура = Ном.Ссылка)
			И (ПоступлениеТоваровУслугТовары.Ссылка.Дата МЕЖДУ &Дата И &ДатаКон)
ГДЕ
	Ном.ЭтоГруппа = ЛОЖЬ
	И ПоступлениеТоваровУслугТовары.Номенклатура ЕСТЬ NULL

В данном случае платформа сначала отберет строки табличной части за указанный период, а затем присоединит их к справочнику. Для элементов номенклатуры, не поступавших в этот период, поле ПоступлениеТоваровУслугТовары.Номенклатура станет NULL, и условие в ГДЕ отработает корректно.

Способ 2. Использование подзапроса с оператором НЕ В

Другим наглядным решением является отбор элементов номенклатуры с помощью конструкции ГДЕ НЕ Номенклатура В (...). Подзапрос собирает все товары, поступавшие за период, а главный запрос выбирает только те позиций номенклатуры, которые не входят в этот список.

Рассмотрим структуру такого запроса:


ВЫБРАТЬ
	Ном.Ссылка КАК Номенклатура
ИЗ
	Справочник.Номенклатура КАК Ном
ГДЕ
	Ном.ЭтоГруппа = ЛОЖЬ
	И НЕ Ном.Ссылка В
		(ВЫБРАТЬ РАЗЛИЧНЫЕ
			ТЧТовары.Номенклатура
		ИЗ
			Документ.ПоступлениеТоваровУслуг.Товары КАК ТЧТовары
		ГДЕ
			ТЧТовары.Ссылка.Дата МЕЖДУ &Дата И &ДатаКон)

Этот способ легко читается, но при больших объемах данных в базе 1С он может уступать по скорости выполнения оптимально построенным левым соединениям.

Способ 3. Оптимизированный пакетный запрос с временной таблицей (Рекомендуемый стандарт)

Если задача выполняется на крупной информационной базе, прямой запрос к табличным частям документов через точку (ПоступлениеТоваровУслугТовары.Ссылка.Дата) создает неявные соединения в SQL и может вызывать проблемы с производительностью. Кроме того, прямое чтение табличной части выбирает данные в том числе из непроведенных или помеченных на удаление документов.

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


ВЫБРАТЬ РАЗЛИЧНЫЕ
	ТЧТовары.Номенклатура КАК Номенклатура
ПОМЕСТИТЬ ВТ_ПоступившиеТовары
ИЗ
	Документ.ПоступлениеТоваровУслуг.Товары КАК ТЧТовары
ГДЕ
	ТЧТовары.Ссылка.Дата МЕЖДУ &Дата И &ДатаКон
	И ТЧТовары.Ссылка.Проведен = ИСТИНА;

ИНОСИРИРОВАТЬ ВТ_ПоступившиеТовары ПО Номенклатура;

ВЫБРАТЬ
	Ном.Ссылка КАК Номенклатура
ИЗ
	Справочник.Номенклатура КАК Ном
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ПоступившиеТовары КАК ВТ_ПоступившиеТовары
		ПО (ВТ_ПоступившиеТовары.Номенклатура = Ном.Ссылка)
ГДЕ
	Ном.ЭтоГруппа = ЛОЖЬ
	И ВТ_ПоступившиеТовары.Номенклатура ЕСТЬ NULL

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

Способ 4. Выборка через виртуальные таблицы регистров накопления

В большинстве конфигураций 1С (таких как ERP, Комплексная автоматизация, Управление торговлей или Бухгалтерия) при проведении документов поступления данные записываются в регистры накопления (например, Закупки или ТоварыНаСкладах).

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


ВЫБРАТЬ
	Ном.Ссылка КАК Номенклатура
ИЗ
	Справочник.Номенклатура КАК Ном
		ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Закупки.Обороты(&ДатаНач, &ДатаКон, Авто, ) КАК ЗакупкиОбороты
		ПО (ЗакупкиОбороты.Номенклатура = Ном.Ссылка)
ГДЕ
	Ном.ЭтоГруппа = ЛОЖЬ
	И ЗакупкиОбороты.Номенклатура ЕСТЬ NULL

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

← На главную