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

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

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

Исходная проблема и анализ типовых ошибок

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


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

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

  1. Использование ПОЛНОГО СОЕДИНЕНИЯ: В данном контексте оно избыточно. Если нам нужны остатки, которые есть на складе, нам достаточно левого соединения с таблицей цен.
  2. Фильтрация в секции ГДЕ: Это самая грубая ошибка при работе с виртуальными таблицами. Условия на Склад и ТипЦены должны передаваться в параметры самих таблиц.
  3. Соединение по наименованию: Сравнение строк (Товар.Наименование) работает крайне медленно и не использует индексы базы данных. Соединять нужно только по ссылочным полям.
  4. Отсутствие обработки NULL: Если для товара не установлена цена, результат умножения будет равен NULL, что может привести к пустотам в отчете.

Шаг 1: Правильное использование виртуальных таблиц

Выясним причину, по которой условия из секции ГДЕ нужно переносить в параметры. Когда мы обращаемся к РегистрНакопления.ТоварыНаСкладах.Остатки, платформа 1С формирует временную таблицу в памяти СУБД. Если мы не укажем параметры (склад, товар), система сначала выгрузит все остатки по всем складам, а уже потом отсечет ненужные. Если записей миллионы, запрос «упадет» по тайм-ауту.

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


// Параметры для Остатки: (Период, Условие)
// Параметры для СрезПоследних: (Период, Условие)

Шаг 2: Оптимизация соединения и работа со ссылками

Заменим ПОЛНОЕ СОЕДИНЕНИЕ на ЛЕВОЕ СОЕДИНЕНИЕ. Это гарантирует, что в результат попадут все товары, имеющиеся на складе, даже если для них еще не назначена цена. Также заменим условие связи ПО. Вместо обращения через точку к наименованию (что является скрытым соединением с таблицей справочника), используем прямые ссылки на объекты Номенклатура (или Товар в зависимости от конфигурации).

Посмотрим на правильное условие связи:

ПО ТоварыНаСкладахОстатки.Товар = ЦеныТоваровСрезПоследних.Товар

Шаг 3: Обработка пустых значений (NULL) и расчет суммы

Для корректного отображения суммы используем конструкцию ВЫБОР или функцию ЕСТЬNULL. Функция ЕСТЬNULL более лаконична и предпочтительна для простых проверок. Она позволяет заменить NULL (отсутствующую цену) на 0, чтобы арифметическая операция прошла успешно.

Проанализируем пример использования функции ВЫБОР для безопасного расчета:


ВЫБОР 
    КОГДА ЦеныТоваровСрезПоследних.Цена ЕСТЬ NULL ТОГДА 0 
    ИНАЧЕ ВЫРАЗИТЬ(ЦеныТоваровСрезПоследних.Цена * ТоварыНаСкладахОстатки.КоличествоОстаток КАК ЧИСЛО(15, 2)) 
КОНЕЦ КАК Сумма

Итоговый оптимизированный запрос

Соберем все рекомендации воедино. Мы перенесли фильтры в параметры виртуальных таблиц, настроили левое соединение по ссылкам и обеспечили безопасность вычислений. Разберем итоговый вариант кода:


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

Важные замечания по производительности

При работе с большими объемами данных в реальных конфигурациях (УТ 11, ERP, КА) следует учитывать дополнительные факторы:

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

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

← На главную