Как правильно извлечь историю статусов и последний статус из регистра сведений без дублирования строк?

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

При построении отчетов в 1С часто возникает необходимость получить одновременно и детальные записи истории изменений объекта (например, конкретные промежуточные статусы задания), и его текущий актуальный статус. Однако при попытке соединить в одном запросе основную таблицу регистра сведений и виртуальную таблицу СрезПоследних разработчики часто сталкиваются с непредвиденным размножением строк среза.

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

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

Проанализируем механику работы СУБД при левом соединении таблиц. В основной физической таблице регистра сведений по одному и тому же заданию хранится множество записей — вся история смены статусов. В то же время виртуальная таблица СрезПоследних для каждого задания содержит строго одну запись с последним актуальным состоянием.

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

Решение 1. Использование конструкции ОБЪЕДИНИТЬ ВСЕ

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

  1. В первой выборке выбираем нужные исторические статусы из основной таблицы регистра сведений РегистрСведений.омСтатусыЗаданий с необходимыми отборами в секции ГДЕ.
  2. Во второй выборке извлекаем запись из виртуальной таблицы РегистрСведений.омСтатусыЗаданий.СрезПоследних.
  3. Связываем выборки с помощью конструкции ОБЪЕДИНИТЬ ВСЕ.

Рассмотрим пример реализации такого запроса:


ВЫБРАТЬ
	Статусы.Задание КАК Задание,
	Статусы.Статус КАК Статус,
	"История" КАК ТипЗаписи
ИЗ
	РегистрСведений.омСтатусыЗаданий КАК Статусы
ГДЕ
	Статусы.Статус В (&Статус1, &Статус2)

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	Срез.Задание КАК Задание,
	Срез.Статус КАК Статус,
	"Актуальный" КАК ТипЗаписи
ИЗ
	РегистрСведений.омСтатусыЗаданий.СрезПоследних(&Период, ) КАК Срез

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

Решение 2. Разворачивание статусов в колонки (СГРУППИРОВАТЬ ПО)

Если бизнес-логика требует вывести строго одну строку на каждое задание, где разные статусы расположены в отдельных колонках, следует использовать группировку и условные функции МАКСИМУМ с конструкцией ВЫБОР КОГДА.

Рассмотрим пример запроса:


ВЫБРАТЬ
	Статусы.Задание КАК Задание,
	МАКСИМУМ(ВЫБОР КОГДА Статусы.Статус = &Статус1 ТОГДА Статусы.Статус ИНАЧЕ NULL КОНЕЦ) КАК Статус1,
	МАКСИМУМ(ВЫБОР КОГДА Статусы.Статус = &Статус2 ТОГДА Статусы.Статус ИНАЧЕ NULL КОНЕЦ) КАК Статус2,
	МАКСИМУМ(Срез.Статус) КАК ПоследнийСтатус
ИЗ
	РегистрСведений.омСтатусыЗаданий КАК Статусы
	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.омСтатусыЗаданий.СрезПоследних(&Период, ) КАК Срез
		ПО Статусы.Задание = Срез.Задание
СГРУППИРОВАТЬ ПО
	Статусы.Задание

Благодаря агрегатной функции МАКСИМУМ и группировке по полю Задание, все дублирующиеся строки сворачиваются в одну уникальную запись по каждому заданию.

Решение 3. Связывание наборов данных в СКД

Если отчет разрабатывается с использованием Системы компоновки данных (СКД), наилучшим архитектурным решением будет разделение запроса на два отдельных набора данных:

  1. НаборДанных1 (Запрос): извлекает историю из основной таблицы регистра.
  2. НаборДанных2 (Запрос): извлекает актуальное состояние из СрезПоследних.

После создания наборов на вкладке «Связи наборов данных» необходимо настроить связь по полю Задание (источник — НаборДанных1, приемник — НаборДанных2). Компоновщик данных 1С самостоятельно выполнит корректное сведение записей без дублирования строк в итоговом отчете.

Важные рекомендации по производительности

При работе с виртуальной таблицей СрезПоследних всегда передавайте условия отбора (например, список заданий или период) напрямую в параметры самой виртуальной таблицы, а не в секцию ГДЕ. Если фильтр указан в ГДЕ, платформа 1С сначала сформирует срез последних по абсолютно всем записям регистра в базе данных, и лишь затем отфильтрует результат, что приведет к падению производительности на больших объемах данных.

← На главную