Как в запросе 1С выбрать данные по каждой строке с учетом индивидуального периода действия соглашения?

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

В практике разработки на платформе 1С:Предприятие 8 часто возникает задача построения отчетов, где период выборки данных зависит не от общего параметра отчета, а от параметров конкретной записи в базе данных. Типичный пример — анализ продаж по соглашениям с клиентами, где каждое соглашение имеет свои уникальные даты начала и окончания действия. Рассмотрим подробно, как реализовать такой запрос, избежать дублирования данных и обойти технические ограничения языка запросов.

Анализ исходной задачи и условий периода

Представим ситуацию: у нас есть таблица соглашений. Для каждого соглашения заданы ДатаНачала, ДатаОкончания и ДатаСоздания. Логика определения рабочего периода следующая:

  1. Если ДатаНачала и ДатаОкончания заполнены, используем их.
  2. Если даты не установлены, соглашение считается действующим с момента ДатаСоздания по текущую дату (бессрочно).

Основная сложность заключается в том, что в одном запросе нам нужно для каждой строки «Соглашение» отобрать свои строки «Реализация», попадающие в этот плавающий интервал.

Способ 1: Использование левого соединения и условий в секции ПО

Разберем вариант решения через прямое соединение справочника соглашений и документов реализации. Чтобы реализовать сложную логику дат, мы можем использовать конструкцию ВЫБОР КОГДА непосредственно в условии связи. Проанализируем пример кода, который позволяет подготовить временную таблицу с актуальными датами:


ВЫБРАТЬ
    Соглашения.Ссылка КАК Соглашение,
    ВЫБОР
        КОГДА Соглашения.ДатаНачалаДействия = ДАТАВРЕМЯ(1, 1, 1)
            ТОГДА Соглашения.Дата
        ИНАЧЕ Соглашения.ДатаНачалаДействия
    КОНЕЦ КАК ДатаНачалаРасчетная,
    ВЫБОР
        КОГДА Соглашения.ДатаОкончанияДействия = ДАТАВРЕМЯ(1, 1, 1)
            ТОГДА &ТекущаяДата
        ИНАЧЕ Соглашения.ДатаОкончанияДействия
    КОНЕЦ КАК ДатаОкончанияРасчетная
ПОМЕСТИТЬ ВТ_ПодготовленныеСоглашения
ИЗ
    Справочник.СоглашенияСКлиентами КАК Соглашения
ГДЕ
    НЕ Соглашения.ПометкаУдаления;

После того как мы нормализовали даты во временной таблице ВТ_ПодготовленныеСоглашения, мы можем выполнить соединение с табличной частью товаров реализации. Обратите внимание, что мы используем ЛЕВОЕ СОЕДИНЕНИЕ, чтобы в отчет попали даже те соглашения, по которым не было продаж.


ВЫБРАТЬ
    ВТ.Соглашение КАК Соглашение,
    РеализацияТовары.Номенклатура КАК Номенклатура,
    СУММА(РеализацияТовары.Количество) КАК Количество
ИЗ
    ВТ_ПодготовленныеСоглашения КАК ВТ
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары
        ПО ВТ.Соглашение = РеализацияТовары.Ссылка.Соглашение
        И РеализацияТовары.Ссылка.Дата МЕЖДУ ВТ.ДатаНачалаРасчетная И ВТ.ДатаОкончанияРасчетная
        И РеализацияТовары.Ссылка.Проведен
СГРУППИРОВАТЬ ПО
    ВТ.Соглашение,
    РеализацияТовары.Номенклатура;

Решение проблемы «Вложенные таблицы не могут выбираться во временную таблицу»

При написании подобных запросов начинающие программисты часто совершают ошибку, пытаясь выбрать табличную часть документа (например, СоглашенияСКлиентами.Товары) как поле в запросе, создающем временную таблицу. Выясним причину ошибки: Временная таблица в 1С — это физическая таблица в СУБД, а реляционные базы данных не поддерживают хранение таблицы внутри ячейки другой таблицы.

Как правильно: Если вам нужны данные из табличной части, их нужно выбирать отдельным соединением. Рассмотрим пример исправления:

Вместо попытки выбрать Соглашение.Товары.*, мы пишем:


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

Оптимизация: Использование регистров накопления

Проанализируем архитектурный аспект. Обращение к табличным частям документов (Документ.РеализацияТоваровУслуг.Товары) — это ресурсоемкая операция, так как СУБД приходится считывать данные из тяжелых таблиц документов. В типовых конфигурациях (УТ 11, ERP, КА 2) для этих целей лучше использовать Регистры накопления (например, ВыручкаИПродажи).

Использование виртуальной таблицы Обороты регистра накопления позволит:

Проблема дублирования данных

При соединении по датам (как предлагалось в одном из сообщений форума) существует риск «задвоения» номенклатуры. Это происходит, если одна и та же реализация формально попадает под условия нескольких соглашений из-за пересечения их периодов. Чтобы этого избежать, всегда приоритезируйте связь по прямой ссылке (Реализация.Соглашение = Соглашение.Ссылка). Если же прямой ссылки нет, необходимо использовать группировку или ключевое слово РАЗЛИЧНЫЕ, чтобы в списке товаров под соглашением не было повторов.

Работа в Системе компоновки данных (СКД)

Если вы разрабатываете отчет, наиболее элегантным решением будет использование Связей наборов данных в СКД. Вы можете создать два набора данных:

  1. НаборДанных1: Выбирает список соглашений и их индивидуальные даты.
  2. НаборДанных2: Выбирает продажи (из регистра или документов).

В настройках связей вы можете передать ДатаНачала и ДатаОкончания из первого набора в параметры второго набора. Это позволит системе автоматически фильтровать продажи для каждого соглашения, обеспечивая высокую производительность и гибкость настроек для пользователя.

Таким образом, комбинируя правильную подготовку данных во временных таблицах и использование механизмов платформы (таких как регистры и СКД), мы получаем надежный инструмент для анализа данных в разрезе динамических периодов.

← На главную