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

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

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

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

Проанализируем ситуацию: разработчик создал обработку, где в качестве основной таблицы динамического списка выбрана таблица Справочник.Номенклатура. Для вывода цен и остатков были подключены левым соединением виртуальные таблицы РегистрСведений.ЦеныНоменклатуры.СрезПоследних и РегистрНакопления.ТоварыНаСкладах.Остатки. На первый взгляд, запрос выглядит логично, но при выполнении возникают ошибки в данных.

Посмотрим на пример «проблемного» запроса:


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

Выясним причину, почему этот код может работать некорректно. Основная проблема здесь кроется в механизме работы ЛЕВОГО СОЕДИНЕНИЯ при отсутствии жестких фильтров в параметрах виртуальных таблиц.

Причина №1: Дублирование строк из-за нескольких складов или видов цен

Если в вашей базе данных числится более одного склада или создано несколько видов цен (например, «Оптовая» и «Розничная»), виртуальная таблица без параметров вернет несколько строк для одной и той же номенклатуры.

Рассмотрим по шагам:

  1. Виртуальная таблица Остатки возвращает данные в разрезе всех измерений регистра (Номенклатура, Склад, Характеристика). Если товар лежит на двух складах, таблица вернет две строки.
  2. При левом соединении справочника с такой таблицей, одна строка номенклатуры превратится в две. Пользователь увидит в списке две одинаковые позиции товара с разными остатками.
  3. Аналогично с ценами: если для товара установлены две разные цены, количество строк в динамическом списке увеличится пропорционально количеству цен.

Причина №2: Отсутствие параметров в виртуальных таблицах

В динамическом списке крайне важно передавать параметры непосредственно в виртуальные таблицы, а не фильтровать результат в секции ГДЕ. Это критично для производительности и корректности данных.

Проанализируем правильный подход. Чтобы динамический список работал корректно, мы должны гарантировать, что для каждой ссылки номенклатуры из левой таблицы найдется строго одна (или ноль) строк в присоединяемых таблицах. Для этого в параметрах виртуальных таблиц необходимо указать отборы по конкретному складу и конкретному виду цен.

Решение: Исправление запроса и использование параметров

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


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

Важные моменты:

Особенности работы с основной таблицей

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

  1. Платформа автоматически генерирует команды контекстного меню (Создать, Пометка на удаление и т.д.).
  2. Оптимизируется выборка данных: 1С считывает только те записи, которые видны пользователю на экране (ленивая загрузка).
  3. Если основная таблица не указана, динамический список может работать значительно медленнее, так как системе сложнее определить уникальный ключ строки.

Однако помните: если ваш запрос из-за неправильных соединений начнет возвращать дубликаты ссылок (несколько строк с одной и той же ссылкой номенклатуры), динамический список может вести себя непредсказуемо — строки могут «прыгать», исчезать или отображать неверную информацию при прокрутке.

Производительность и использование СКД

Динамические списки в управляемых формах работают на базе Системы компоновки данных (СКД). Это мощный инструмент, который позволяет пользователю самостоятельно настраивать отборы.

Рассмотрим ситуацию, когда пользователь хочет отфильтровать список по складу. Если мы просто добавим поле Склад в выборку, платформа выполнит соединение, а затем отфильтрует результат. Это медленно. Правильнее использовать механизм автоматического заполнения параметров. Если в настройках динамического списка включено использование параметров СКД, то отборы, установленные пользователем, будут автоматически «пробрасываться» внутрь виртуальных таблиц, что значительно ускорит работу системы на больших объемах данных.

Что делать, если нужны остатки по всем складам сразу?

Иногда задача стоит иначе: нужно видеть общую сумму остатка по всем складам в одной строке номенклатуры. В этом случае соединение с виртуальной таблицей Остатки без параметра Склад все равно приведет к дублям.

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

Резюме для разработчика

Чтобы ваш динамический список работал быстро и корректно, придерживайтесь следующих правил:

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

← На главную