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

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

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

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

Почему виртуальная таблица остатков не возвращает нули?

Для оптимизации объема базы данных и быстродействия СУБД платформа 1С хранит итоги регистров накопления только по ненулевым значениям ресурсов. Если товар полностью списан со склада, итоговая запись обнуляется и удаляется из таблицы итогов.

Виртуальная таблица РегистрНакопления.ТоварыВСкладскихЯчейках.Остатки формирует выборку исключительно на основе актуальных остатков. Если по переданной комбинации измерений остатка нет, виртуальная таблица возвращает пустой результат (0 строк), а не строку с числом 0.

Кроме того, в исходном запросе автора допущены две критические ошибки:

  1. Условия в секции ГДЕ вместо параметров виртуальной таблицы: когда отборы по измерениям (Склад, Номенклатура, ЯчейкаСклада) накладываются через ГДЕ, СУБД сначала рассчитывает остатки по всей таблице регистра, и лишь затем отсекает лишние строки. Это существенно снижает производительность. Фильтры необходимо передавать напрямую в параметры виртуальной таблицы.
  2. Условие КоличествоОстаток <> &КоличествоОстаток: подобное условие бессмысленно и полностью блокирует получение нужных данных.

Способ 1. Левое соединение со справочником номенклатуры

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

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


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

Способ 2. Выборка по конкретным параметрам без чтения справочников

Если задача заключается в проверке строго одной конкретной позиции (заданной параметрами &Номенклатура, &Склад, &ЯчейкаСклада), обращаться к физической таблице справочника не обязательно. Мы можем сформировать исходную строку непосредственно из параметров запроса и присоединить к ней виртуальную таблицу остатков.

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


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

В этом случае запрос гарантированно возвращает ровно одну строку. Если остаток есть — вернется его фактическое значение, если остатка нет — поле КоличествоОстаток примет значение 0.

Способ 3. Использование временной таблицы для списка позиций

Если требуется получить остатки по произвольному списку товаров (например, переданному из документа или массива), наиболее производительным решением будет загрузка списка во временную таблицу с последующим соединением.

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


ВЫБРАТЬ
	ИсходныйСписок.Номенклатура КАК Номенклатура,
	&Склад КАК Склад,
	&ЯчейкаСклада КАК ЯчейкаСклада
ПОМЕСТИТЬ ВТ_ТоварыДляПроверки
ИЗ
	&ТаблицаТоваров КАК ИсходныйСписок
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	ВТ_ТоварыДляПроверки.Номенклатура КАК Номенклатура,
	ВТ_ТоварыДляПроверки.Склад КАК Склад,
	ВТ_ТоварыДляПроверки.ЯчейкаСклада КАК ЯчейкаСклада,
	ЕСТЬNULL(ТоварыВСкладскихЯчейкахОстатки.КоличествоОстаток, 0) КАК КоличествоОстаток
ИЗ
	ВТ_ТоварыДляПроверки КАК ВТ_ТоварыДляПроверки
		ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыВСкладскихЯчейках.Остатки(
				&Период,
				Склад = &Склад
					И ЯчейкаСклада = &ЯчейкаСклада
					И Номенклатура В
						(ВЫБРАТЬ
							ВТ_ТоварыДляПроверки.Номенклатура
						ИЗ
							ВТ_ТоварыДляПроверки)) КАК ТоварыВСкладскихЯчейкахОстатки
		ПО ВТ_ТоварыДляПроверки.Номенклатура = ТоварыВСкладскихЯчейкахОстатки.Номенклатура

Способ 4. Использование виртуальной таблицы «ОстаткиИОбороты»

Если цель состоит в том, чтобы найти только те позиции, которые ранее находились в ячейке, но к выбранному моменту были полностью списаны (то есть конечный остаток равен 0 при наличии движений), используем таблицу ОстаткиИОбороты.

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


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

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

← На главную