Как правильно получить остатки и резервы в разрезе складов в запросе 1С, включая позиции с нулевым остатком?

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

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

Разбор ошибки «Поле не найдено»

Рассмотрим ситуацию, когда при попытке соединить несколько таблиц остатков система выдает ошибку Поле не найдено "ИмяТаблицы.Склад". Проанализируем причину на примере исходного запроса автора темы. Ошибка возникает из-за того, что программист пытается обратиться к псевдониму таблицы в секции ПО до того, как эта таблица была объявлена или присоединена. В языке запросов 1С порядок соединений критически важен: нельзя использовать поля таблицы Б в условии связи таблицы А, если таблица Б идет в тексте запроса позже.

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

Оптимальная архитектура: объединение вместо соединения

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

  1. Производительность: SQL-серверу гораздо проще выполнить несколько простых выборок и объединить их в один поток, чем рассчитывать сложные условия соединений (JOIN) между виртуальными таблицами.
  2. Прозрачность: Вы сразу видите, какие ресурсы и показатели вытягиваются из каждого регистра.
  3. Отсутствие дублей: При соединении таблиц по нескольким измерениям (Номенклатура, Склад, Характеристика) легко ошибиться в условиях ПО, что приведет к «размножению» строк. В случае с объединением эта проблема исключена.

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


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

ОБЪЕДИНИТЬ ВСЕ

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

Как вывести товары с нулевыми остатками («Шахматка»)

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

Разберем по шагам процесс создания такой матрицы:

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

Рассмотрим пример кода для построения матрицы:


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

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

ВЫБРАТЬ
    ВТ_Номенклатура.Номенклатура,
    ВТ_Склады.Склад
ПОМЕСТИТЬ ВТ_Матрица
ИЗ
    ВТ_Номенклатура КАК ВТ_Номенклатура,
    ВТ_Склады КАК ВТ_Склады
;

Итоговая сборка данных с использованием ЕСТЬNULL

Теперь, когда у нас есть «пустая» сетка ВТ_Матрица и заполненная данными ВТ_СводныеДанные, мы можем их соединить. Очень важно использовать функцию ЕСТЬNULL, так как для отсутствующих на складах товаров придет значение NULL, которое нельзя складывать или вычитать.

Проанализируем итоговый запрос:


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

Важные советы по оптимизации

Для того чтобы ваш отчет работал быстро даже в крупных базах данных (например, в 1С:Комплексная автоматизация), соблюдайте следующие правила:

  1. Параметры виртуальных таблиц: Всегда передавайте условия (Склад, Номенклатура) в параметры виртуальных таблиц Остатки(...). Никогда не фильтруйте их в секции ГДЕ, иначе система сначала прочитает все итоги базы, а потом будет их отсекать.
  2. Индексация: Если во временных таблицах ВТ_Номенклатура или ВТ_СводныеДанные ожидается более 100-200 строк, обязательно добавьте команду ИНДЕКСИРОВАТЬ ПО для полей связи.
  3. Вложенные запросы: Избегайте слишком глубокой вложенности. Старайтесь разбивать сложную логику на последовательные временные таблицы. Это упрощает отладку через консоль запросов и помогает планировщику SQL выбрать оптимальный путь исполнения.

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

← На главную