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

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

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

Почему в виртуальных таблицах нет нулей

Прежде всего, проанализируем ситуацию: почему обычный запрос к регистру не показывает отсутствующие товары? Виртуальная таблица Остатки работает на основе итогов. Если по конкретной комбинации измерений (Номенклатура, Склад) нет записи или сумма ресурсов стала равна нулю, 1С просто не возвращает такую строку. Чтобы получить в отчете «красивую» таблицу, где напротив каждого склада стоит либо число, либо ноль, нам придется использовать данные из справочников.

Шаг 1. Создание «матрицы» комбинаций (Декартово произведение)

Чтобы вывести все склады для выбранной номенклатуры, нам нужно сначала создать структуру, в которой каждая выбранная позиция товара будет сопоставлена с каждым интересующим нас складом. В языке запросов 1С это достигается путем соединения двух таблиц без указания конкретного условия связи (или с условием ПО ИСТИНА).

Рассмотрим пример формирования такой временной таблицы:


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

В данном фрагменте кода мы создаем таблицу ВТ_Матрица, которая содержит все возможные пары «Товар — Склад». Это критически важный этап: если товара нет на складе «Основной», в этой таблице запись все равно будет существовать.

Шаг 2. Получение реальных остатков

Теперь нам нужно получить текущие остатки из регистра и поместить их в другую временную таблицу. Важно накладывать фильтры по номенклатуре и складам уже на уровне параметров виртуальной таблицы — это значительно ускоряет работу запроса.


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

Шаг 3. Соединение данных и обработка значений NULL

Разберем финальный этап. Мы берем нашу «матрицу» (где есть все пары) и левым соединением присоединяем к ней таблицу с реальными остатками. Если остатка нет, поле из таблицы остатков будет содержать NULL. Нам остается лишь заменить его на 0 с помощью функции ЕСТЬNULL.


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

Типичные ошибки при реализации

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

  1. Фильтрация в предложении ГДЕ: Если вы наложите условие ГДЕ ВТ_Остатки.Склад = &Склад в последнем запросе пакета, вы снова потеряете нулевые остатки. Любая фильтрация по полям «правой» таблицы в левом соединении превращает его во внутреннее соединение. Всегда делайте отборы в параметрах виртуальных таблиц или в условиях формирования «матрицы».
  2. Отсутствие индексации: При работе с большими объемами данных (много товаров и много складов) соединение временных таблиц без индексов может «положить» сервер. Всегда используйте ИНДЕКСИРОВАТЬ ПО для полей связи.
  3. Использование ПОЛНОГО СОЕДИНЕНИЯ: В некоторых СУБД (например, PostgreSQL) полное соединение работает медленнее, чем левое. Рекомендуется сначала формировать эталонную таблицу (левую часть), а затем присоединять к ней данные.

Использование СКД для вывода нулей

Если ваша задача — построить отчет в Системе компоновки данных (СКД), то городить сложные Cross Join в запросе не обязательно. Рассмотрим альтернативный путь:

Заключение

Мы выяснили причину отсутствия нулей в выборках и разобрали надежный способ их получения. Помните, что получение «пустых» данных всегда требует наличия эталонного списка (справочника), с которым производится сравнение. Использование временных таблиц и функции ЕСТЬNULL — это стандарт индустрии для решения подобных задач в 1С.

← На главную