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

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

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

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

Причина 1: Превращение левого соединения во внутреннее из-за секции ГДЕ

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


ГДЕ
    НЕ СпрНоменклатура.ЭтоГруппа
    И ТоварыНаСкладахОстатки.Склад.Наименование = "1. Склад (Ленинский)"
    И ТоварыНаСкладахОстаткиДаниловская.Склад.Наименование = "2, Склад (Даниловская)"
    И ТоварыНаСкладахЛенинский30.Склад.Наименование = "3. Розничный магазин Л-30"

Выясним причину такого поведения СУБД. Когда левое соединение не находит подходящую запись в присоединяемой таблице остатков (например, если товара нет на складе), во всех полях этой таблицы возвращается значение NULL. Затем СУБД переходит к проверке условий из блока ГДЕ. Так как значение NULL не равно текстовому наименованию склада, такое условие возвращает ЛОЖЬ. В результате вся строка справочника Справочник.Номенклатура полностью исключается из итоговой выборки.

Таким образом, логика ЛЕВОЕ СОЕДИНЕНИЕ фактически превращается во ВНУТРЕННЕЕ СОЕДИНЕНИЕ (INNER JOIN). Для исправления этой ошибки необходимо перенести отбор по присоединяемой таблице из секции ГДЕ в секцию описания связи ПО.

Посмотрим на пример правильного оформления связи:


ИЗ
    Справочник.Номенклатура КАК СпрНоменклатура
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки
        ПО (ТоварыНаСкладахОстатки.Номенклатура = СпрНоменклатура.Ссылка)
            И (ТоварыНаСкладахОстатки.Склад.Наименование = "1. Склад (Ленинский)")
        
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстаткиДаниловская
        ПО (ТоварыНаСкладахОстаткиДаниловская.Номенклатура = СпрНоменклатура.Ссылка)
            И (ТоварыНаСкладахОстаткиДаниловская.Склад.Наименование = "2, Склад (Даниловская)")
        
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахЛенинский30
        ПО (ТоварыНаСкладахЛенинский30.Номенклатура = СпрНоменклатура.Ссылка)
            И (ТоварыНаСкладахЛенинский30.Склад.Наименование = "3. Розничный магазин Л-30")

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

Причина 2: Неправильная работа с параметрами виртуальной таблицы и поиск по наименованию

Использование поиска реквизитов через Склад.Наименование = "..." является крайне неэффективным по нескольким причинам:

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

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


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

Значение параметра &СкладЛенинский задается в настройках динамического списка или программно при открытии формы.

Причина 3: Пропала возможность заходить в карточку товара

Рассмотрим вторую проблему: после модификации запроса при нажатии на строку номенклатуры перестал открываться элемент справочника.

Это происходит из-за того, что платформе 1С при существенном изменении структуры запроса динамического списка необходимо явно указать главную таблицу выборки. Платформа сбрасывает значение свойства Основная таблица динамического списка.

Выясним, как восстановить функциональность карточки номенклатуры:

  1. Откройте форму списка номенклатуры в конфигураторе.
  2. Перейдите на вкладку Элементы или Реквизиты и выберите реквизит динамического списка (обычно Список).
  3. В панели свойств найдите строку Основная таблица.
  4. Укажите значение Справочник.Номенклатура.

После указания основной таблицы платформа снова привяжет стандартные команды формы к выбранному справочнику: станут доступны открытие формы элемента, контекстное меню, проверка прав RLS и стандартный поиск.

Альтернативный подход: Использование события ПриПолученииДанныхНаСервере

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

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

Алгоритм данного подхода выглядит следующим образом:

  1. В событии ПриПолученииДанныхНаСервере платформа передает массив ссылок только тех товаров, которые отображаются на экране пользователя в данный момент (как правило, от 20 до 50 строк).
  2. Выполняется один быстрый запрос к регистру остатков с фильтром по полученному массиву ссылок номенклатуры и нужным складам.
  3. Результат запроса подставляется в допечатываемые ячейки или свойства оформляемых строк формы.

Применение этого метода гарантирует максимально высокую скорость работы интерфейса независимо от объема базы данных и количества складов.

← На главную