При разработке отчетов в системе «1С:Предприятие» одной из самых частых задач является получение актуальных остатков товаров вместе с их стоимостной оценкой (ценой). Начинающие разработчики часто сталкиваются с проблемами производительности и логическими ошибками при соединении различных типов регистров. В этой статье мы подробно разберем, как написать эффективный запрос, проанализируем типичные ошибки и выясним, как оптимизировать работу с виртуальными таблицами.
Рассмотрим ситуацию: нам необходимо получить список товаров на конкретном складе, их количество и рассчитать сумму, исходя из заданного типа цен. Часто первая попытка написать такой запрос выглядит следующим образом:
ВЫБРАТЬ
ТоварыНаСкладахОстатки.Склад.Наименование КАК СкладНаименование,
ТоварыНаСкладахОстатки.Товар.Наименование КАК ТоварНаименование,
ТоварыНаСкладахОстатки.КоличествоОстаток КАК КоличествоОстаток,
ВЫРАЗИТЬ(ЦеныТоваровСрезПоследних.Цена * ТоварыНаСкладахОстатки.КоличествоОстаток КАК ЧИСЛО(15, 2)) КАК Сумма
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки
ПОЛНОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныТоваров.СрезПоследних КАК ЦеныТоваровСрезПоследних
ПО ТоварыНаСкладахОстатки.Товар.Наименование = ЦеныТоваровСрезПоследних.Товар.Наименование
ГДЕ
ТоварыНаСкладахОстатки.Склад = &Склад
И ЦеныТоваровСрезПоследних.ТипЦены = &ТипЦены
Проанализируем этот код и выделим критические недостатки, которые могут привести к медленной работе системы или неверным данным:
Склад и ТипЦены должны передаваться в параметры самих таблиц.Товар.Наименование) работает крайне медленно и не использует индексы базы данных. Соединять нужно только по ссылочным полям.NULL, что может привести к пустотам в отчете.Выясним причину, по которой условия из секции ГДЕ нужно переносить в параметры. Когда мы обращаемся к РегистрНакопления.ТоварыНаСкладах.Остатки, платформа 1С формирует временную таблицу в памяти СУБД. Если мы не укажем параметры (склад, товар), система сначала выгрузит все остатки по всем складам, а уже потом отсечет ненужные. Если записей миллионы, запрос «упадет» по тайм-ауту.
Рассмотрим, как правильно передать параметры в виртуальную таблицу Остатки() и СрезПоследних():
// Параметры для Остатки: (Период, Условие)
// Параметры для СрезПоследних: (Период, Условие)
Заменим ПОЛНОЕ СОЕДИНЕНИЕ на ЛЕВОЕ СОЕДИНЕНИЕ. Это гарантирует, что в результат попадут все товары, имеющиеся на складе, даже если для них еще не назначена цена. Также заменим условие связи ПО. Вместо обращения через точку к наименованию (что является скрытым соединением с таблицей справочника), используем прямые ссылки на объекты Номенклатура (или Товар в зависимости от конфигурации).
Посмотрим на правильное условие связи:
ПО ТоварыНаСкладахОстатки.Товар = ЦеныТоваровСрезПоследних.Товар
Для корректного отображения суммы используем конструкцию ВЫБОР или функцию ЕСТЬNULL. Функция ЕСТЬNULL более лаконична и предпочтительна для простых проверок. Она позволяет заменить NULL (отсутствующую цену) на 0, чтобы арифметическая операция прошла успешно.
Проанализируем пример использования функции ВЫБОР для безопасного расчета:
ВЫБОР
КОГДА ЦеныТоваровСрезПоследних.Цена ЕСТЬ NULL ТОГДА 0
ИНАЧЕ ВЫРАЗИТЬ(ЦеныТоваровСрезПоследних.Цена * ТоварыНаСкладахОстатки.КоличествоОстаток КАК ЧИСЛО(15, 2))
КОНЕЦ КАК Сумма
Соберем все рекомендации воедино. Мы перенесли фильтры в параметры виртуальных таблиц, настроили левое соединение по ссылкам и обеспечили безопасность вычислений. Разберем итоговый вариант кода:
ВЫБРАТЬ
ТоварыНаСкладахОстатки.Склад КАК Склад,
ТоварыНаСкладахОстатки.Товар КАК Товар,
ТоварыНаСкладахОстатки.КоличествоОстаток КАК Количество,
ЕСТЬNULL(ЦеныТоваровСрезПоследних.Цена, 0) КАК Цена,
ВЫРАЗИТЬ(ЕСТЬNULL(ЦеныТоваровСрезПоследних.Цена, 0) * ТоварыНаСкладахОстатки.КоличествоОстаток КАК ЧИСЛО(15, 2)) КАК Сумма
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(, Склад = &Склад) КАК ТоварыНаСкладахОстатки
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныТоваров.СрезПоследних(, ТипЦены = &ТипЦены) КАК ЦеныТоваровСрезПоследних
ПО ТоварыНаСкладахОстатки.Товар = ЦеныТоваровСрезПоследних.Товар
При работе с большими объемами данных в реальных конфигурациях (УТ 11, ERP, КА) следует учитывать дополнительные факторы:
ПОМЕСТИТЬ ВТ_Остатки), проиндексировать её по полю Товар, а затем соединять с ценами. Это помогает оптимизатору SQL построить более предсказуемый план запроса.СебестоимостьТоваров или ПартииТоваровНаСкладах). Там сумма уже рассчитана и хранится в ресурсах, что избавляет от необходимости умножения в запросе.ПО, иначе вы получите неверные данные (цена одной характеристики может умножиться на остаток другой).Таким образом, мы рассмотрели процесс создания запроса от типичных ошибок до оптимизированного решения. Правильное использование виртуальных таблиц и механизмов соединения — залог стабильной работы информационной системы.