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

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

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

Выясним причину проблемы и особенности работы запросов

Проанализируем, почему простой запрос с левым соединением не дает нужного результата:

  1. Конструкция ПЕРВЫЕ 1 ограничивает количество записей во всей выборке запроса, а не внутри каждой группы по контрагенту.
  2. Прямое соединение справочника Справочник.Контрагенты с табличной частью или документом событий без предварительного получения максимальной даты вернет все документы по каждому контрагенту.
  3. Обращение «через точку» к реквизитам шапки из табличных частей (например, СобытиеУчастники.Ссылка.НачалоСобытия) создает неявные соединения, что может снижать производительность и приводить к некорректной фильтрации.

Решение 1: Пакетный запрос с временными таблицами

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

Шаг 1. Получение максимальной даты события для каждого контрагента

Сначала выберем всех контрагентов и максимальную дату начала события для каждого из них, поместив результат во временную таблицу ВТ_МаксДаты.


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

Шаг 2. Разрешение коллизии одинаковых дат и выбор конкретного документа

Если у одного контрагента есть несколько событий с абсолютно одинаковой датой и временем, соединение по дате вернет дубли строк. Чтобы избежать этого, выберем максимальную ссылку на документ (МАКСИМУМ(Ссылка)) для каждой пары контрагента и максимальной даты.


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

Шаг 3. Итоговое левое соединение со справочником контрагентов

Теперь свяжем полный справочник Справочник.Контрагенты с нашей временной таблицей ВТ_ПоследниеСобытия и с шапкой документа события. Контрагенты, у которых не было ни одного события, останутся в отчете с пустыми полями.


ВЫБРАТЬ
	Контрагенты.Ссылка КАК Контрагент,
	ПоследниеСобытия.Событие КАК Событие,
	ДокументСобытие.НачалоСобытия КАК Дата,
	ДокументСобытие.ТипСобытия КАК ТипСобытия,
	ДокументСобытие.Содержание КАК Содержание,
	ДокументСобытие.Ответственный КАК Автор
ИЗ
	Справочник.Контрагенты КАК Контрагенты
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ПоследниеСобытия КАК ПоследниеСобытия
		ПО Контрагенты.Ссылка = ПоследниеСобытия.Контрагент
		ЛЕВОЕ СОЕДИНЕНИЕ Документ.Событие КАК ДокументСобытие
		ПО ПоследниеСобытия.Событие = ДокументСобытие.Ссылка
УПОРЯДОЧИТЬ ПО
	Контрагенты.Наименование
;

Решение 2: Использование двух наборов данных в СКД

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

Рассмотрим пошагово порядок настройки схемы компоновки данных:

  1. Создание первого набора данных (НаборДанных_Контрагенты): Добавим набор данных - запрос, который выбирает весь список контрагентов из справочника Справочник.Контрагенты.
  2. Создание второго набора данных (НаборДанных_События): Добавим второй набор данных - запрос, который выбирает сведения о событии с ограничением по параметру:
    
    ВЫБРАТЬ ПЕРВЫЕ 1
    	СобытиеУчастники.Ссылка КАК Событие,
    	СобытиеУчастники.Ссылка.НачалоСобытия КАК Дата,
    	СобытиеУчастники.Ссылка.Содержание КАК Содержание
    ИЗ
    	Документ.Событие.Участники КАК СобытиеУчастники
    ГДЕ
    	СобытиеУчастники.Контрагент = &Контрагент
    УПОРЯДОЧИТЬ ПО
    	СобытиеУчастники.Ссылка.НачалоСобытия УБЫВ
    
  3. Настройка связей наборов данных: Перейдем на вкладку Связи наборов данных.
    • Источник связи: НаборДанных_Контрагенты.
    • Приемник связи: НаборДанных_События.
    • Условие связи: Ссылка (поле контрагента из первого набора).
    • Параметр: Контрагент.

При такой настройке СКД выполняет главный запрос по контрагентам, а затем для каждой полученной строки передает текущую ссылку на контрагента в параметр &Контрагент второго набора данных. Конструкция ПЕРВЫЕ 1 корректно отрабатывает для каждого контрагента отдельно, а левое соединение сохраняет пустые строки для контрагентов без событий.

Рекомендации по повышению производительности

При работе с большими объемами данных учтем следующие ключевые моменты:

  1. Обязательно используем инструкцию ИНДЕКСИРОВАТЬ ПО во временных таблицах по полям, участвующим в условиях последующих соединений (в нашем примере это поля Контрагент и Дата).
  2. Если база данных содержит документы за несколько лет, целесообразно ограничить выборку событий по периоду (например, за последний год), добавив условие ГДЕ НачалоСобытия >= &ДатаНачала на первом этапе формирования временной таблицы.
← На главную