Как правильно вывести нулевые остатки товаров на складах в разрезе характеристик в 1С

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

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

Анализ проблемы: почему исчезают нулевые остатки

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

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

Решение 1: Правильное использование левого соединения

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

  1. Все фильтры по справочным данным (вид номенклатуры, группа, свойства) должны накладываться на левую (основную) таблицу.
  2. Фильтры по измерениям регистра (склад) должны передаваться в параметры виртуальной таблицы, а не в секцию ГДЕ.

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


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

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

Решение 2: Формирование «Полной матрицы» (Cross Join)

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

Для решения этой задачи мы применим метод создания кросс-таблицы (декартова произведения). Разберем по шагам:

  1. Сначала мы выбираем всю необходимую Номенклатуру и её Характеристики.
  2. Затем мы соединяем этот результат со справочником Склады без условия связи. Это создаст в памяти комбинацию «Каждый товар — Каждая характеристика — Каждый склад».
  3. К полученной «матрице» мы присоединяем реальные остатки из регистра.

Пример реализации через временные таблицы:


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

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

Особенности работы с СКД (Система компоновки данных)

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

Во-первых, в настройках набора данных для измерений (Номенклатура, Характеристика, Склад) можно установить роль «Обязательное». Это заставит СКД всегда включать эти поля в выборку.

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

Важные технические нюансы

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

Таким образом, мы рассмотрели несколько подходов к выводу нулевых остатков. Выбор конкретного метода зависит от сложности структуры отчета и используемых инструментов (чистый запрос или СКД). Главное правило — всегда контролировать, на какую таблицу накладываются условия фильтрации, чтобы не потерять данные при левом соединении.

← На главную