Как правильно соединить остатки с ценами в запросе 1С и вывести их в отчет без потери данных?

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

В практике разработчика 1С часто возникает задача построения отчета, который объединяет данные из разных регистров. Типичный пример — получение остатков товаров на складах вместе с актуальными ценами из регистра сведений. На первый взгляд задача кажется простой, но она таит в себе подводные камни как на уровне написания запроса, так и на этапе вывода данных в табличный документ. Рассмотрим пошагово, как реализовать этот механизм правильно и избежать распространенных ошибок.

Разбор типичной проблемы: почему пропадают данные в отчете?

Рассмотрим ситуацию, когда запрос написан, данные в консоли запросов отображаются, но при выводе в макет колонки (например, «Цена» или «Артикул») остаются пустыми. Проанализируем фрагмент кода, который часто становится причиной такой проблемы:


Пока ВыборкаДетальныеЗаписи.Следующий Цикл
    // ОШИБКА: Ручное присвоение до вызова Заполнить()
    ОбластьДетальныхЗаписей.Параметры.Цена = ВыборкаДетальныеЗаписи.Цена;
    ОбластьДетальныхЗаписей.Параметры.Артикул1 = ВыборкаДетальныеЗаписи.Артикул;
    
    // Этот метод может затереть установленные выше значения
    ОбластьДетальныхЗаписей.Параметры.Заполнить(ВыборкаДетальныеЗаписи);
    
    ТабДок.Вывести(ОбластьДетальныхЗаписей, ВыборкаДетальныеЗаписи.Уровень);
КонецЦикла;

Выясним причину такого поведения. Метод Заполнить() объекта Параметры области макета предназначен для автоматического копирования значений из источника (в нашем случае — выборки запроса) в параметры макета с совпадающими именами. Если в выборке запроса поле называется Цена, а в макете параметр тоже называется Цена, метод выполнит присваивание.

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

Правильный порядок действий в коде:


Пока ВыборкаДетальныеЗаписи.Следующий Цикл
    // 1. Сначала заполняем всё, что совпадает по именам
    ОбластьДетальныхЗаписей.Параметры.Заполнить(ВыборкаДетальныеЗаписи);
    
    // 2. Затем дозаполняем или корректируем специфические параметры
    ОбластьДетальныхЗаписей.Параметры.Цена = ВыборкаДетальныеЗаписи.Цена;
    ОбластьДетальныхЗаписей.Параметры.Артикул1 = ВыборкаДетальныеЗаписи.Артикул;
    
    ТабДок.Вывести(ОбластьДетальныхЗаписей, ВыборкаДетальныеЗаписи.Уровень);
КонецЦикла;

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

Теперь проанализируем сам запрос. Прямое левое соединение двух виртуальных таблиц Остатки и СрезПоследних — это ресурсоемкая операция, которая может привести к деградации производительности при увеличении объема данных. Разберем, как сделать работу системы более стабильной.

В исходном варианте запрос выглядит так:


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

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

  1. Индексация: Мы можем поместить остатки во временную таблицу и проиндексировать их по полю Номенклатура. Это значительно ускорит операцию соединения.
  2. Фильтрация: Мы передаем параметры (склад, номенклатура) непосредственно в параметры виртуальной таблицы Остатки(&Период, Склад = &Склад). Это позволяет серверу СУБД выбрать только нужные записи, а не сканировать весь регистр.

Рекомендуемая структура запроса через временные таблицы

Посмотрим на пример оптимизированного запроса:


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

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

Важные аспекты работы с ценами

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

  1. Тип цен: Регистр ЦеныНоменклатуры практически всегда имеет измерение ТипЦен (Оптовая, Розничная и т.д.). Если в левом соединении не указать фильтр по конкретному типу цен, запрос может вернуть несколько строк на одну позицию номенклатуры (по одной строке для каждого типа цены), что приведет к «раздуванию» остатков в отчете.
  2. Обработка NULL: При использовании ЛЕВОЕ СОЕДИНЕНИЕ, если для товара цена не установлена, в поле Цена придет значение NULL. В макете это будет выглядеть как пустая ячейка. Использование функции ЕСТЬNULL(Цена, 0) позволяет корректно вывести нулевое значение.
  3. Дата среза: Если в параметрах виртуальной таблицы не указать дату &Период, система вернет данные на текущий момент (включая текущую секунду). Для формирования отчетов «на начало дня» или «на вчера» обязательно используйте объект Граница или передавайте конкретную дату.

Заключение

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

← На главную