Разберем классическую задачу разработчика 1С: сформировать отчет со списком всей номенклатуры, где в отдельные колонки выводятся оптовая и розничная цены, а также остатки по основному и дополнительному складам. Начинающие специалисты часто сталкиваются с ситуацией, когда данные задваиваются, пропадают позиции с нулевым остатком или платформа выдает синтаксические ошибки при попытке обработать пустые значения.
Проанализируем типичные ошибки, выясним их причины и построим корректный, производительный запрос на базе конфигурации «1С:Управление торговлей 11».
Рассмотрим, почему первоначальный запрос может возвращать неверные результаты или вызывать ошибки платформы 1С:
РегистрНакопления.ТоварыНаСкладах или РегистрСведений.ЦеныНоменклатуры возвращает все движения за всю историю, а не актуальные остатки на дату или срез последних цен. Для получения актуальных данных необходимо обращаться к виртуальным таблицам ТоварыНаСкладах.Остатки и ЦеныНоменклатуры.СрезПоследних.ЛЕВОЕ СОЕДИНЕНИЕ с таблицей остатков, а затем в блоке ГДЕ указывается условие ТоварыНаСкладах.Склад = &Склад, то все строки номенклатуры, по которым нет остатка (где склад равен NULL), отсекаются. Запрос превращается во внутреннее соединение. Параметры складов и типов цен нужно передавать непосредственно в параметры виртуальных таблиц.Остаток к именам числовых ресурсов. Например, ресурс ВНаличии в виртуальной таблице ТоварыНаСкладах.Остатки превращается в поле ВНаличииОстаток.?(,,). Любые условные конструкции в запросе строятся исключительно через выражение ВЫБОР КОГДА ... ТОГДА ... ИНАЧЕ ... КОНЕЦ.Разберем по шагам создание надежного пакетного запроса, который выбирает весь список номенклатуры, левым соединением подтягивает срезы цен и остатки по каждому складу.
СрезПоследних.Остатки с фильтром по первому складу.ЕСТЬNULL.Посмотрим на полный текст итогового запроса:
ВЫБРАТЬ
СпрНоменклатура.Ссылка КАК Ссылка,
СпрНоменклатура.Наименование КАК Наименование,
МАКСИМУМ(ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0)) КАК Цена,
МАКСИМУМ(ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних1.Цена, 0)) КАК Розница
ПОМЕСТИТЬ ВТ_СЦенами
ИЗ
Справочник.Номенклатура КАК СпрНоменклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(, ВидЦены = &Опт) КАК ЦеныНоменклатурыСрезПоследних
ПО (ЦеныНоменклатурыСрезПоследних.Номенклатура = СпрНоменклатура.Ссылка)
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(, ВидЦены = &Розница) КАК ЦеныНоменклатурыСрезПоследних1
ПО (ЦеныНоменклатурыСрезПоследних1.Номенклатура = СпрНоменклатура.Ссылка)
ГДЕ
СпрНоменклатура.ЭтоГруппа = ЛОЖЬ
СГРУППИРОВАТЬ ПО
СпрНоменклатура.Ссылка,
СпрНоменклатура.Наименование
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
ТоварыНаСкладахОстатки.ВНаличииОстаток КАК ВНаличииОстаток
ПОМЕСТИТЬ ОстатокНаОсновномСкладе
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(
,
(Склад, Номенклатура) В
(ВЫБРАТЬ
&Склад,
ВТ_СЦенами.Ссылка
ИЗ
ВТ_СЦенами КАК ВТ_СЦенами)) КАК ТоварыНаСкладахОстатки
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
ТоварыНаСкладахОстатки.ВНаличииОстаток КАК ВНаличииОстаток
ПОМЕСТИТЬ ОстатокВадан
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(
,
(Склад, Номенклатура) В
(ВЫБРАТЬ
&СкладВАДАН,
ВТ_СЦенами.Ссылка
ИЗ
ВТ_СЦенами КАК ВТ_СЦенами)) КАК ТоварыНаСкладахОстатки
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_СЦенами.Ссылка КАК Номенклатура,
ВТ_СЦенами.Наименование КАК Наименование,
ВТ_СЦенами.Цена КАК Цена,
ВТ_СЦенами.Розница КАК Розница,
ЕСТЬNULL(ОстатокНаОсновномСкладе.ВНаличииОстаток, 0) КАК ВНаличии,
ЕСТЬNULL(ОстатокВадан.ВНаличииОстаток, 0) КАК ВНаличииВАДАН
ИЗ
ВТ_СЦенами КАК ВТ_СЦенами
ЛЕВОЕ СОЕДИНЕНИЕ ОстатокНаОсновномСкладе КАК ОстатокНаОсновномСкладе
ПО ВТ_СЦенами.Ссылка = ОстатокНаОсновномСкладе.Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ ОстатокВадан КАК ОстатокВадан
ПО ВТ_СЦенами.Ссылка = ОстатокВадан.Номенклатура
Рассмотрим подробнее задачу, когда вместо числового остатка требуется выводить статус доступности товара по определенному правилу:
Для этого в финальном пакете запроса заменим прямое поле остатка на условную конструкцию ВЫБОР:
ВЫБОР
КОГДА ЕСТЬNULL(ОстатокНаОсновномСкладе.ВНаличииОстаток, 0) > 0
ТОГДА ОстатокНаОсновномСкладе.ВНаличииОстаток
ИНАЧЕ ВЫБОР
КОГДА ЕСТЬNULL(ОстатокВадан.ВНаличииОстаток, 0) > 0
ТОГДА "Под заказ 7 дней"
ИНАЧЕ ""
КОНЕЦ
КОНЕЦ КАК СтатусНаличия
Обратим внимание на важные детали архитектуры «1С:Управление торговлей 11» при разработке подобных отчетов:
ТоварыНаСкладах учет ведется в разрезе номенклатуры, характеристик, серий и назначений. Если на предприятии используются характеристики, выборка остатка без группировки по номенклатуре приведет к дублированию строк. При получении остатков исключительно в разрезе номенклатуры обязательно используйте агрегатную функцию СУММА(ВНаличииОстаток) и секцию СГРУППИРОВАТЬ ПО.ВНаличииОстаток регистра ТоварыНаСкладах отражает фактическое физическое количество товаров. Если в отчете требуется отображать свободный остаток за вычетом резервов, данные необходимо получать из специализированных регистров подсистемы запасов (например, РаспределениеЗапасов).ТоварыНаСкладах.Остатки с фильтром по списку складов Склад В (&МассивСкладов), а разделение по колонкам реализовать с помощью конструкции СУММА(ВЫБОР КОГДА Склад = &ОсновнойСклад ТОГДА ВНаличииОстаток ИНАЧЕ 0 КОНЕЦ).