Почему СрезПоследних добавляет лишние строки в запрос и как получить одну актуальную запись

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

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

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


ВЫБРАТЬ
	Физлица.ФизЛицо КАК ФизЛицо,
	ПлановыеНачисления.ВидРасчета КАК ВидРасчета
ИЗ
	ВТФизлица КАК Физлица
	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПлановыеНачисленияРаботниковОрганизаций.СрезПоследних(&КонецПериода, ) КАК ПлановыеНачисления
		ПО Физлица.ФизЛицо = ПлановыеНачисления.Сотрудник.ФизЛицо

Ожидается, что на каждое физическое лицо в результат попадет только одна актуальная запись на указанную дату, однако на практике строк становится значительно больше. Выясним причины такого поведения платформы «1С:Предприятие».

Причины задвоения строк при использовании среза последних

Рассмотрим ключевые факторы, влияющие на количество строк, возвращаемых виртуальной таблицей:

  1. Множественность измерений регистра: Виртуальная таблица СрезПоследних вычисляет наиболее позднюю запись не по какому-то одному выбранному полю, а по каждой уникальной комбинации всех измерений регистра сведений. Например, если в регистре ПлановыеНачисленияРаботниковОрганизаций присутствуют измерения Организация, Сотрудник, ВидРасчетаИзмерение и ДокументОснование, платформа вернет срез для каждого набора этих измерений. Если у сотрудника назначено несколько разных видов начислений (оклад, премия, надбавка), по каждому из них будет возвращена своя последняя строка.
  2. Связь «один ко многим» между физлицами и сотрудниками: В кадровом учете 1С справочник ФизическиеЛица отделен от справочника Сотрудники. Одному физическому лицу может соответствовать несколько элементов справочника сотрудников (например, основное место работы и внутреннее/внешнее совместительство, либо повторный прием на работу после увольнения). Соединение Физлица.ФизЛицо = ПлановыеНачисления.Сотрудник.ФизЛицо возвращает данные по всем рабочим местам данного человека.
  3. Регистры, подчиненные регистратору: Для непериодических или периодических регистров, подчиненных регистратору, уникальность среза может определяться не только измерениями и датой, но и полями Регистратор и НомерСтроки.
  4. Неоптимальность виртуальной таблицы в соединениях: Обращение к СрезПоследних в секции ЛЕВОЕ СОЕДИНЕНИЕ без указания параметров отбора внутри самой виртуальной таблицы заставляет СУБД рассчитывать срез по всему объему регистра в базе данных, что приводит к критическому падению производительности.

Вариант 1. Получение максимальной даты через группировку (ручной срез)

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


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

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

Вариант 2. Двухэтапная выборка через временные таблицы

Для оптимизации быстродействия и полного контроля над количеством строк по стандартам разработки 1С рекомендуется отказаться от использования виртуальной таблицы в левом соединении и выполнить построение собственного среза через физическую таблицу регистра и временные таблицы:


// Шаг 1. Получаем список сотрудников и максимальную дату начисления до нужного момента
ВЫБРАТЬ
	Начисления.Сотрудник КАК Сотрудник,
	МАКСИМУМ(Начисления.Период) КАК Период
ПОМЕСТИТЬ ВТ_МаксимальныеДаты
ИЗ
	РегистрСведений.ПлановыеНачисленияРаботниковОрганизаций КАК Начисления
ГДЕ
	Начисления.Период <= &Дата
СГРУППИРОВАТЬ ПО
	Начисления.Сотрудник
;

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

// Шаг 3. Соединяем с исходной таблицей физических лиц
ВЫБРАТЬ
	Физлица.ФизЛицо КАК ФизЛицо,
	Начисления.ВидРасчета КАК ВидРасчета,
	Начисления.Показатель1 КАК РазмерОклада
ИЗ
	ВТФизлица КАК Физлица
	ЛЕВОЕ СОЕДИНЕНИЕ ВТ_МаксимальныеРегистраторы КАК ИтогСрез
		ПО Физлица.ФизЛицо = ИтогСрез.Сотрудник.ФизЛицо
		И ИтогСрез.Сотрудник.ВидЗанятости = ЗНАЧЕНИЕ(Перечисление.ВидыЗанятостиВОрганизации.ОсновноеМестоРаботы)
	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПлановыеНачисленияРаботниковОрганизаций КАК Начисления
		ПО ИтогСрез.Сотрудник = Начисления.Сотрудник
		И ИтогСрез.Период = Начисления.Период
		И ИтогСрез.Регистратор = Начисления.Регистратор

Рассмотренный трехшаговый алгоритм гарантирует:

  1. Отсутствие лишних дублей по физлицу за счет фильтрации по виду занятости ОсновноеМестоРаботы.
  2. Получение строго одной последней записи даже при наличии нескольких документов на одну дату за счет свертки по максимальному регистратору.
  3. Высокую скорость выполнения запроса без лишней нагрузки на СУБД, так как обращение происходит к реальной таблице с использованием индексов.
← На главную