При разработке произвольных форм часто возникает задача вывести список номенклатуры не просто перечнем из справочника, а с актуальными ценами и остатками на складах. Начинающие разработчики часто сталкиваются с ситуацией, когда данные в списке начинают «двоиться», или по каждой позиции отображается общая сумма остатков по всей базе. Рассмотрим, почему это происходит и как правильно спроектировать запрос для динамического списка.
Проанализируем ситуацию: разработчик создал обработку, где в качестве основной таблицы динамического списка выбрана таблица Справочник.Номенклатура. Для вывода цен и остатков были подключены левым соединением виртуальные таблицы РегистрСведений.ЦеныНоменклатуры.СрезПоследних и РегистрНакопления.ТоварыНаСкладах.Остатки. На первый взгляд, запрос выглядит логично, но при выполнении возникают ошибки в данных.
Посмотрим на пример «проблемного» запроса:
ВЫБРАТЬ
СправочникНоменклатура.Ссылка КАК Ссылка,
СправочникНоменклатура.Код КАК Код,
СправочникНоменклатура.Наименование КАК Наименование,
ЦеныНоменклатурыСрезПоследних.Цена КАК Цена,
ЕСТЬNULL(ТоварыНаСкладахОстатки.ВНаличииОстаток, 0) КАК ВНаличии
ИЗ
Справочник.Номенклатура КАК СправочникНоменклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних КАК ЦеныНоменклатурыСрезПоследних
ПО (ЦеныНоменклатурыСрезПоследних.Номенклатура = СправочникНоменклатура.Ссылка)
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки
ПО ТоварыНаСкладахОстатки.Номенклатура = СправочникНоменклатура.Ссылка
Выясним причину, почему этот код может работать некорректно. Основная проблема здесь кроется в механизме работы ЛЕВОГО СОЕДИНЕНИЯ при отсутствии жестких фильтров в параметрах виртуальных таблиц.
Если в вашей базе данных числится более одного склада или создано несколько видов цен (например, «Оптовая» и «Розничная»), виртуальная таблица без параметров вернет несколько строк для одной и той же номенклатуры.
Рассмотрим по шагам:
Остатки возвращает данные в разрезе всех измерений регистра (Номенклатура, Склад, Характеристика). Если товар лежит на двух складах, таблица вернет две строки.В динамическом списке крайне важно передавать параметры непосредственно в виртуальные таблицы, а не фильтровать результат в секции ГДЕ. Это критично для производительности и корректности данных.
Проанализируем правильный подход. Чтобы динамический список работал корректно, мы должны гарантировать, что для каждой ссылки номенклатуры из левой таблицы найдется строго одна (или ноль) строк в присоединяемых таблицах. Для этого в параметрах виртуальных таблиц необходимо указать отборы по конкретному складу и конкретному виду цен.
Для того чтобы исправить ситуацию, нам необходимо отредактировать текст запроса динамического списка и добавить обязательные параметры. Разберем, как должен выглядеть правильный запрос:
ВЫБРАТЬ
СправочникНоменклатура.Ссылка КАК Ссылка,
СправочникНоменклатура.Код КАК Код,
СправочникНоменклатура.Наименование КАК Наименование,
ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0) КАК Цена,
ЕСТЬNULL(ТоварыНаСкладахОстатки.ВНаличииОстаток, 0) КАК ВНаличии
ИЗ
Справочник.Номенклатура КАК СправочникНоменклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ВидЦены = &ВидЦены) КАК ЦеныНоменклатурыСрезПоследних
ПО (ЦеныНоменклатурыСрезПоследних.Номенклатура = СправочникНоменклатура.Ссылка)
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад) КАК ТоварыНаСкладахОстатки
ПО (ТоварыНаСкладахОстатки.Номенклатура = СправочникНоменклатура.Ссылка)
Важные моменты:
&Период позволяет получать актуальные данные на нужную дату.ВидЦены = &ВидЦены гарантирует, что мы получим только одну цену для одного товара.Склад = &Склад отсекает остатки по другим складам, предотвращая «размножение» строк.ЕСТЬNULL обязательна для числовых полей, чтобы при отсутствии данных (когда товара нет на складе) в списке отображался «0», а не пустое значение. Это важно для корректной сортировки.При настройке динамического списка в 1С 8.3 крайне рекомендуется указывать Основную таблицу (в нашем случае Справочник.Номенклатура). Это дает несколько преимуществ:
Однако помните: если ваш запрос из-за неправильных соединений начнет возвращать дубликаты ссылок (несколько строк с одной и той же ссылкой номенклатуры), динамический список может вести себя непредсказуемо — строки могут «прыгать», исчезать или отображать неверную информацию при прокрутке.
Динамические списки в управляемых формах работают на базе Системы компоновки данных (СКД). Это мощный инструмент, который позволяет пользователю самостоятельно настраивать отборы.
Рассмотрим ситуацию, когда пользователь хочет отфильтровать список по складу. Если мы просто добавим поле Склад в выборку, платформа выполнит соединение, а затем отфильтрует результат. Это медленно. Правильнее использовать механизм автоматического заполнения параметров. Если в настройках динамического списка включено использование параметров СКД, то отборы, установленные пользователем, будут автоматически «пробрасываться» внутрь виртуальных таблиц, что значительно ускорит работу системы на больших объемах данных.
Иногда задача стоит иначе: нужно видеть общую сумму остатка по всем складам в одной строке номенклатуры. В этом случае соединение с виртуальной таблицей Остатки без параметра Склад все равно приведет к дублям.
Для решения такой задачи проанализируем использование сгруппированного подзапроса или (что более правильно для 1С) использование параметров виртуальной таблицы. Если нам нужен общий остаток, мы можем не указывать склад в параметрах, но обязаны использовать агрегатные функции в запросе, предварительно сгруппировав данные по номенклатуре. Однако в динамических списках группировки использовать нельзя, если указана основная таблица. В такой ситуации лучше всего выводить остатки через отдельную виртуальную таблицу, которая уже содержит просуммированные данные (если это предусмотрено архитектурой регистра), либо пересмотреть требования к интерфейсу.
Чтобы ваш динамический список работал быстро и корректно, придерживайтесь следующих правил:
СрезПоследних, Остатки) параметрами (вид цены, склад, дата).Ссылка). В результирующей выборке не должно быть двух строк с одинаковой ссылкой.ЕСТЬNULL для полей, участвующих в расчетах или сортировке.Следуя этим рекомендациям, вы сможете создавать эффективные и удобные интерфейсы для работы с большими массивами данных, избегая «детских болезней» начинающих разработчиков 1С.