В процессе разработки отчетов на базе Системы компоновки данных (СКД) программисты часто сталкиваются с задачей получения остатков товаров именно на дату конкретного документа. Основная сложность заключается в том, что язык запросов 1С не позволяет напрямую передать поле из одной таблицы (например, ПланЗакупок.Дата) в качестве параметра виртуальной таблицы другой (РегистрНакопления.ТоварыНаСкладах.Остатки) внутри одного соединения. Рассмотрим подробнее, как решить эту задачу эффективно и правильно.
Разберем типичную ситуацию, с которой столкнулся автор темы. В запросе делается попытка соединить таблицу документов с виртуальной таблицей остатков. Проблема в том, что параметры виртуальных таблиц (такие как &ДатаПлана) вычисляются единожды перед выполнением всего запроса. Если в отчет попадает несколько документов с разными датами, система не сможет «подставить» свою дату для каждой строки автоматически через обычное левое соединение.
Проанализируем исходный код запроса, который вызывает затруднения:
ВЫБРАТЬ
НачальныеОстатки.КоличествоОстаток КАК НачальныйОстаток
ИЗ
Документ.ПланЗакупок КАК ПланЗакупок
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(&ДатаПлана, ) КАК НачальныеОстатки
ПО ПланЗакупок.Номенклатура = НачальныеОстатки.Номенклатура
Здесь параметр &ДатаПлана является статичным для всего результирующего набора. Если нам нужно получить остатки на дату конкретного документа (через поле Ссылка), мы должны использовать механизмы СКД или изменить структуру запроса.
Одним из ключевых моментов в СКД является механизм расширения языка запросов. Чтобы система компоновки данных могла гибко управлять параметрами и отборами, используются фигурные скобки {}. Как справедливо отмечено в обсуждении, это «самое главное» для корректной работы параметров в виртуальных таблицах.
Рассмотрим исправленный вариант запроса для отчета по конкретному документу:
ВЫБРАТЬ
ПланЗакупокСоставПлана.Номенклатура,
ПланЗакупокСоставПлана.Количество КАК Потребность,
ТоварыНаСкладахОстатки.КоличествоОстаток КАК ОстатокНаДату
ИЗ
Документ.ПланЗакупок.СоставПлана КАК ПланЗакупокСоставПлана
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки({&ДатаОстатков}, ) КАК ТоварыНаСкладахОстатки
ПО ПланЗакупокСоставПлана.Номенклатура = ТоварыНаСкладахОстатки.Номенклатура
ГДЕ
ПланЗакупокСоставПлана.Ссылка = &Ссылка
В данном случае, когда мы указываем {&ДатаОстатков}, мы даем СКД возможность перехватить этот параметр. Если мы установим значение &ДатаОстатков в настройках отчета или программно, СКД подставит его в подзапрос получения остатков. Это работает хорошо, если мы формируем отчет по одному конкретному документу, переданному через параметр &Ссылка.
Выясним причину, почему предыдущий способ не подходит для списка документов с разными датами. Если документов много, параметр остатков все равно будет один на всех. В этом случае нам поможет самый мощный механизм СКД — Связи наборов данных. Проанализируем пошаговый алгоритм решения:
ПланЗакупок (Номенклатура, ДатаПланирования, Ссылка).ТоварыНаСкладах.Остатки(&Период, ). В параметре указываем стандартное имя &Период.НаборДанных1, Приемник: НаборДанных2.Номенклатура = Номенклатура.Период, а в колонке "Выражение источника" выбираем ДатаПланирования из первого набора.Благодаря такой настройке, СКД для каждой строки из первого набора (для каждого документа) выполнит отдельный запрос к виртуальной таблице остатков, подставляя дату этого конкретного документа в параметр &Период. Это единственный штатный способ получить динамические остатки в одном отчете без использования физических таблиц регистра.
Проанализируем ситуацию, когда остатки выводятся некорректно. Часто программисты жалуются, что остатки «не видят» движения самого документа. Рассмотрим, почему это происходит:
Если в параметр &ДатаОстатков передать просто дату документа (например, 01.01.2023 12:00:00), 1С получит остатки на начало этой секунды. Движения документа, сделанные в эту же самую секунду, не будут включены в результат.
Чтобы включить движения документа в остаток, необходимо использовать объект Граница. В выражениях параметров СКД это можно прописать следующим образом:
Выражение для параметра &ДатаОстатков:
ДОБАВИТЬКДАТЕ(КонецПериода(&ДатаДокумента, "Секунда"), "Секунда", 1)
Или, если используется программная установка значений:
Параметр = КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти("ДатаОстатков");
Параметр.Значение = Новый Граница(ВыбраннаяДата, ВидГраницы.Включая);
Параметр.Использование = Истина;
Мы разобрали основные способы передачи даты в параметры запроса СКД. Для простых отчетов по одному объекту достаточно использования фигурных скобок и правильной настройки параметров в консоли СКД. Для сложных аналитических отчетов, оперирующих списком документов с разными датами, единственно правильным подходом будет использование связей нескольких наборов данных.
Помните, что работа с виртуальными таблицами требует понимания того, как платформа 1С транслирует ваш запрос в SQL. Использование связей наборов данных порождает множество мелких запросов к базе, поэтому всегда ограничивайте выборку данных в наборе-источнике (например, по периоду или конкретной ссылке), чтобы сохранить высокую производительность вашего отчета.