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