К статье
Практический материал

Разработка и Конфигурация · 12 мин

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

Как вывести в запросе 1С номенклатуру с нулевыми остатками: левое соединение, ЕСТЬNULL, виртуальные таблицы остатков, настройка СКД. Примеры кода и типичные ошибки.

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

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

Ниже разобраны рабочие конструкции запроса, условия их применения, проверка результата и типичные ошибки, из-за которых нулевые строки теряются или, наоборот, отчёт раздувается до неприемлемого размера.

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

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

Следствие простое: любой запрос вида ВЫБРАТЬ Номенклатура, КоличествоОстаток ИЗ ...Остатки по определению не содержит нулей. Добавление условия ГДЕ КоличествоОстаток = 0 ничего не даст — таких строк в источнике нет. Чтобы увидеть нулевые позиции, нужно расширить выборку за счёт другого источника данных: справочника номенклатуры, таблицы оборотов или собственной таблицы нужных позиций.

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

Способ 1. Левое соединение справочника с таблицей остатков

Базовый приём: источником данных делается справочник Номенклатура, а таблица остатков присоединяется слева. Все позиции справочника попадут в результат, а там, где остатка нет, поле будет содержать NULL.

ВЫБРАТЬ

Номенклатура.Ссылка КАК Товар,

ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток

ИЗ

Справочник.Номенклатура КАК Номенклатура

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

ПО Номенклатура.Ссылка = Остатки.Номенклатура

ГДЕ

НЕ Номенклатура.ЭтоГруппа

И НЕ Номенклатура.ПометкаУдаления

Функция ЕСТЬNULL заменяет пустое значение на ноль — без неё в отчёте вместо остатка будет пустая ячейка, а сравнения с нулём в последующих условиях работать не будут, потому что NULL = 0 даёт не «истину», а NULL.

Обязательно отфильтруйте группы и помеченные на удаление элементы, иначе в отчёт попадут папки справочника и «мусорные» позиции. Если нужны только товары определённого вида или группы, добавьте соответствующее условие в секцию ГДЕ — это заметно сократит выборку.

Способ 2. Остатки и обороты: позиции, у которых были движения

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

Таблица ОстаткиИОбороты возвращает строки по всем комбинациям измерений, по которым были движения в заданном периоде, даже если конечный остаток нулевой. Это ключевое отличие от таблицы Остатки: позиция, пришедшая и полностью ушедшая внутри периода, в выборке присутствует с нулевым конечным остатком.

ВЫБРАТЬ

ОстаткиИОбороты.Номенклатура КАК Товар,

ОстаткиИОбороты.КоличествоНачальныйОстаток КАК НачальныйОстаток,

ОстаткиИОбороты.КоличествоПриход КАК Приход,

ОстаткиИОбороты.КоличествоРасход КАК Расход,

ОстаткиИОбороты.КоличествоКонечныйОстаток КАК КонечныйОстаток

ИЗ

РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, , , ) КАК ОстаткиИОбороты

Ограничение способа: товар без единого движения за период в выборку не попадёт. Если нужен и этот сценарий, комбинируйте подходы — левое соединение справочника с ОстаткиИОбороты, а не с Остатки.

Сравнение вариантов

Левое соединение со справочником

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

ОстаткиИОбороты

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

СКД со связью наборов

Гибкая настройка без изменения текста запроса, нули подставляются автоматически. Требует аккуратной настройки связей и ролей.

Способ 3. Фильтрация по нулевому остатку и отбор нужных позиций

Часто нужны не все позиции, а только те, у которых остаток именно нулевой — например, для отчёта «Товары, закончившиеся на складе». Здесь левое соединение дополняется условием на NULL или на результат ЕСТЬNULL.

ВЫБРАТЬ

Номенклатура.Ссылка КАК Товар,

ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток

ИЗ

Справочник.Номенклатура КАК Номенклатура

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

ПО Номенклатура.Ссылка = Остатки.Номенклатура

ГДЕ

НЕ Номенклатура.ЭтоГруппа

И ЕСТЬNULL(Остатки.КоличествоОстаток, 0) = 0

Обратите внимание на параметры виртуальной таблицы: условие по складу передаётся в параметры Остатки(&Период, Склад = &Склад), а не в секцию ГДЕ. Это и быстрее (отбор выполняется на уровне итогов), и безопаснее для логики соединения.

Если отбор строится по списку конкретных товаров (например, из заказа или инвентаризации), эффективнее передать список во временную таблицу через параметр-таблицу значений и соединяться с ней, а не со всем справочником. На больших базах это сокращает время выполнения на порядки.

Порядок действий
  1. 1
    Определите состав позиций: весь справочник, товары с движениями или конкретный список.
  2. 2
    Выберите источник: левое соединение со справочником, таблица ОстаткиИОбороты или временная таблица.
  3. 3
    Отфильтруйте группы и помеченные на удаление элементы справочника.
  4. 4
    Оберните поля остатков в ЕСТЬNULL(Поле, 0).
  5. 5
    Перенесите условия по измерениям регистра в параметры виртуальной таблицы.
  6. 6
    Проверьте результат на заведомо нулевой позиции и сравните итоги с типовым отчётом по остаткам.

Нулевые остатки в СКД без изменения запроса

В системе компоновки данных задача решается на уровне схемы. Если в отчёте два набора данных — справочник номенклатуры и остатки регистра — их связывают на закладке «Связи наборов данных» по полю «Номенклатура» с типом связи «Левое внешнее». Тогда позиции без остатков попадут в отчёт, а в ресурсах останется пустое значение.

Чтобы вместо пустоты выводился ноль, в выражении ресурса на закладке «Ресурсы» используйте ЕСТЬNULL(Сумма(КоличествоОстаток), 0) либо задайте вычисляемое поле с заменой NULL. Альтернатива — на закладке «Настройки» в параметрах вывода установить для поля оформление «Текст при пустом значении», но это влияет только на отображение, а не на расчёты.

Для остатков по периодам в СКД важны роли полей: у поля периода остатков должна быть заполнена роль (период, тип периода), иначе СКД не сможет корректно дополнить таблицу датами и нулевыми промежуточными значениями. Дополнение периодов настраивается в свойствах поля группировки — «Тип дополнения: День/Неделя/Месяц».

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

Отрицательные и развёрнутые остатки

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

Отрицательные остатки в виртуальной таблице присутствуют как обычные строки, поэтому условие <= 0 их отберёт. Если нужно различить «ровно ноль» и «минус», используйте два отдельных условия или вычисляемое поле-признак. Для поиска расхождений после инвентаризации удобен отчёт, где одновременно выводятся начальный остаток, обороты и конечный остаток — нулевой конечный остаток при ненулевых оборотах сразу виден.

Проверка результата и типичные ошибки

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

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

Типичные ошибки
01
Условие по полю остатков в секции ГДЕ — левое соединение превращается во внутреннее, нулевые строки пропадают.
02
Отсутствие ЕСТЬNULL — в результате NULL вместо нуля, сравнения и итоги работают некорректно.
03
Отбор по складу в секции ГДЕ вместо параметров виртуальной таблицы — медленный запрос и риск потери строк.
04
Включение групп справочника в выборку — в отчёте появляются папки с нулевыми остатками.
05
Ожидание нулей от таблицы Остатки — она их не возвращает по определению, нужна ОстаткиИОбороты или соединение.
Контрольные точки

Как проверить результат

Полностью списанный товар
Норма

Присутствует в выборке с остатком 0

Тревожный признак

Строки нет — соединение работает как внутреннее

Сумма остатков по запросу
Норма

Совпадает с типовым отчётом по остаткам

Тревожный признак

Расходится — проверьте параметры периода и отборы

Пустые ячейки в колонке остатка
Норма

Все пустоты заменены нулями через ЕСТЬNULL

Тревожный признак

Есть NULL — сортировка и сравнения будут некорректны

Группы справочника
Норма

В выборке только элементы

Тревожный признак

Присутствуют папки с нулевым остатком

FAQ: частые вопросы о нулевых остатках в запросах 1С

Можно ли получить нулевые остатки без левого соединения?

Частично — через таблицу ОстаткиИОбороты, которая показывает нулевые конечные остатки по позициям с движениями за период. Но товары вообще без движений без соединения со справочником получить невозможно: регистр о них ничего не знает.

Почему ЕСТЬNULL не работает и в отчёте всё равно пусто?

Чаще всего функция применена не к тому полю, которое реально выводится, или замена сделана в запросе, а в СКД ресурс переопределён без ЕСТЬNULL. Проверьте выражение ресурса на закладке «Ресурсы» и вычисляемые поля — они имеют приоритет над текстом запроса.

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

Используйте СКД с дополнением периодов: у группировки по дате задайте тип дополнения «День» и укажите границы периода. Либо постройте запрос с таблицей календаря (временная таблица дат) и левым соединением остатков на каждую дату.

Запрос со всем справочником работает очень медленно. Что делать?

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

Чем отличается Остатки от ОстаткиИОбороты для этой задачи?

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

Как вывести товары, которых нет на одном складе, но которые есть на других?

Сделайте левое соединение декартова произведения справочника и списка складов с таблицей остатков (сначала временная таблица «Товары × Склады», затем соединение с Остатки). Строки с ЕСТЬNULL(Остаток, 0) = 0 и покажут отсутствующие позиции по каждому складу.

Итог

Что важно запомнить

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