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

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

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

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

Анализ типичных ошибок при составлении запроса

Рассмотрим, почему первоначальный запрос может возвращать неверные результаты или вызывать ошибки платформы 1С:

  1. Использование физических таблиц вместо виртуальных: Прямое обращение к физической таблице РегистрНакопления.ТоварыНаСкладах или РегистрСведений.ЦеныНоменклатуры возвращает все движения за всю историю, а не актуальные остатки на дату или срез последних цен. Для получения актуальных данных необходимо обращаться к виртуальным таблицам ТоварыНаСкладах.Остатки и ЦеныНоменклатуры.СрезПоследних.
  2. Фильтрация соединенных таблиц в секции ГДЕ: Если к справочнику номенклатуры применяется ЛЕВОЕ СОЕДИНЕНИЕ с таблицей остатков, а затем в блоке ГДЕ указывается условие ТоварыНаСкладах.Склад = &Склад, то все строки номенклатуры, по которым нет остатка (где склад равен NULL), отсекаются. Запрос превращается во внутреннее соединение. Параметры складов и типов цен нужно передавать непосредственно в параметры виртуальных таблиц.
  3. Неправильные имена полей в виртуальных таблицах остатков: В виртуальной таблице остатков платформа 1С автоматически добавляет суффикс Остаток к именам числовых ресурсов. Например, ресурс ВНаличии в виртуальной таблице ТоварыНаСкладах.Остатки превращается в поле ВНаличииОстаток.
  4. Попытка использовать тернарный оператор встроенного языка: В языке запросов 1С нельзя использовать тернарный оператор ?(,,). Любые условные конструкции в запросе строятся исключительно через выражение ВЫБОР КОГДА ... ТОГДА ... ИНАЧЕ ... КОНЕЦ.

Пошаговое построение запроса с использованием временных таблиц

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

  1. Выборка номенклатуры и цен: В первой временной таблице получаем список номенклатуры и левым соединением получаем оптовую и розничную цены из виртуальной таблицы СрезПоследних.
  2. Получение остатков по основному складу: Во второй временной таблице выбираем остатки из виртуальной таблицы Остатки с фильтром по первому складу.
  3. Получение остатков по дополнительному складу: В третьей временной таблице получаем остатки по складу «ВАДАН».
  4. Финальная сборка данных: Соединяем временные таблицы и выводим итоговые значения, обрабатывая пустые значения функцией ЕСТЬNULL.

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


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

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

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

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

Реализация сложной логики вывода статусов наличия

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

  1. Если товар есть на основном складе — выводим количество остатка на основном складе.
  2. Если товара нет на основном складе, но он есть на складе «ВАДАН» — выводим текст «Под заказ 7 дней».
  3. Если товара нет ни на одном из складов — оставляем поле пустым.

Для этого в финальном пакете запроса заменим прямое поле остатка на условную конструкцию ВЫБОР:


ВЫБОР
	КОГДА ЕСТЬNULL(ОстатокНаОсновномСкладе.ВНаличииОстаток, 0) > 0
		ТОГДА ОстатокНаОсновномСкладе.ВНаличииОстаток
	ИНАЧЕ ВЫБОР
			КОГДА ЕСТЬNULL(ОстатокВадан.ВНаличииОстаток, 0) > 0
				ТОГДА "Под заказ 7 дней"
			ИНАЧЕ ""
		КОНЕЦ
КОНЕЦ КАК СтатусНаличия

Рекомендации по оптимизации и особенности конфигурации УТ 11

Обратим внимание на важные детали архитектуры «1С:Управление торговлей 11» при разработке подобных отчетов:

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