Как вытащить номенклатуру с нулевыми остатками в 1С: подробное руководство

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

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

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

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

Рассмотрим классическую ошибку начинающего разработчика:


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

Этот запрос всегда будет возвращать пустой результат, так как условие ГДЕ применяется к выборке, в которой нулей изначально нет. Чтобы получить нули, нам нужно оттолкнуться от справочника Номенклатура.

Решение №1: Левое соединение со справочником и проверка на NULL

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

Разберем рабочий пример запроса:


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

Что здесь происходит:

  1. Мы берем основной таблицей Справочник.Номенклатура.
  2. Присоединяем к ней остатки. Если товара на складе нет, соединение не найдет соответствия, и в поле ТоварыНаСкладахОстатки.Номенклатура появится NULL.
  3. Условие ГДЕ ТоварыНаСкладахОстатки.Номенклатура ЕСТЬ NULL фильтрует список, оставляя только те позиции, по которым в регистре нет записей.

Решение №2: Использование временных таблиц для оптимизации

Как отмечается в рекомендациях ИТС, прямые соединения с виртуальными таблицами могут приводить к неоптимальным планам запросов в SQL, особенно при больших объемах данных. Если в вашей базе десятки тысяч наименований номенклатуры, лучше использовать механизм временных таблиц.

Рассмотрим, как правильно структурировать пакетный запрос:


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

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

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

Важные нюансы и "подводные камни"

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

  1. Исключение групп и удаленных элементов: Справочник номенклатуры содержит папки (группы) и позиции, помеченные на удаление. Если их не отсечь условиями Товар.ЭтоГруппа = ЛОЖЬ и Товар.ПометкаУдаления = ЛОЖЬ, ваш отчет будет забит "мусорными" записями.
  2. Фильтрация по типу номенклатуры: В 1С часто хранятся не только товары, но и услуги. У услуг нет и не может быть остатков на складах. Чтобы не видеть услуги в списке нулевых остатков, добавьте фильтр: Товар.ТипНоменклатуры = ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Товар).
  3. Разрез характеристик: Если вы ведете учет по характеристикам, ситуация усложняется. Товар может иметь остаток 10 штук в одной характеристике и 0 в другой. Если вам нужно найти товары, которых нет совсем, используйте группировку по ссылке номенклатуры. Если же нужно найти конкретные пустые характеристики — соединение нужно делать по таблице характеристик.
  4. Учет по складам: Если необходимо найти нулевые остатки на конкретном складе, условие по складу обязательно нужно передавать в параметры виртуальной таблицы: Остатки(&ВыбраннаяДата, Склад = &НужныйСклад). Если вы поставите фильтр по складу в секции ГДЕ, товары, которых нет на этом складе, вообще не попадут в выборку из-за специфики LEFT JOIN.

Никогда не было vs Закончился

Рассмотрим интересный момент: существует два состояния "нуля".

Поэтому самым надежным способом проверки является использование функции ЕСТЬNULL(КоличествоОстаток, 0) = 0 при условии, что мы берем за основу справочник Номенклатура.

Итоги

Для эффективного вытаскивания номенклатуры с нулевыми остатками мы выяснили следующее:

Следуя этим правилам, вы получите точный и быстрый инструмент для анализа складских запасов, который не пропустит ни одной позиции.

← На главную