Почему срез последних возвращает несколько записей по одному объекту и как это исправить

Программист 1С v8.3 (Обычные формы) Бухгалтерский учет Сфера услуг, туризм и социальный сектор
← На главную

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

Понимаем логику работы виртуальной таблицы СрезПоследних

Для начала проанализируем фундаментальный принцип: виртуальная таблица СрезПоследних строится не просто по времени (периоду), а по совокупности всех измерений регистра. Рассмотрим это на примере регистра «Местонахождение ОС».

Если в регистре определены три измерения — ОС, ИнвентарныйНомер и Учреждение, то система считает уникальной записью каждую комбинацию этих полей. Срез последних возвращает наиболее позднюю запись для каждой уникальной комбинации измерений.

Представим ситуацию: за одним объектом справочника ОсновныеСредства закреплено несколько инвентарных номеров (групповой учет). Для системы запись с «Инв. №1» и запись с «Инв. №2» — это разные ключевые записи. Если мы в запросе делаем соединение только по полю ОС, мы неизбежно получим в результат столько строк, сколько актуальных инвентарных номеров числится за этим объектом.

Решение 1: Уточнение условий связи по всем измерениям

Самая распространенная ошибка — неполное условие в секции ПО при соединении таблиц. Разберем типичный пример некорректного кода:


ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.МестонахождениеОС.СрезПоследних КАК МестонахождениеОССрезПоследних
ПО БС_ПриходТоваровТаблицаТоваров.Товар.НаименованиеОбъекта = МестонахождениеОССрезПоследних.ОС

Здесь мы связываем таблицу только по одному измерению. Чтобы «схлопнуть» результат до одной строки, нам необходимо добавить в условие связи все остальные измерения, которые есть в регистре. Проанализируем исправленный вариант:


ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.МестонахождениеОС.СрезПоследних КАК МестонахождениеОССрезПоследних
ПО БС_ПриходТоваровТаблицаТоваров.Товар.НаименованиеОбъекта = МестонахождениеОССрезПоследних.ОС
И БС_ПриходТоваровТаблицаТоваров.ИнвНомер = МестонахождениеОССрезПоследних.ИнвНомер
И БС_ПриходТоваровТаблицаТоваров.Учреждение = МестонахождениеОССрезПоследних.Учреждение

Важный момент: если какое-то из измерений в таблице источника отсутствует, нам нужно либо заранее получить его, либо признать, что срез последних без этого измерения всегда будет возвращать избыточные данные.

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

Рассмотрим еще один важный аспект оптимизации и корректности. Условия, наложенные в секции ГДЕ, работают уже после того, как виртуальная таблица была сформирована в памяти. Это не только замедляет работу, но и иногда мешает получению верного среза.

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


ВЫБРАТЬ
    МестонахождениеОССрезПоследних.Состояние
ИЗ
    РегистрСведений.МестонахождениеОС.СрезПоследних(&ДатаСреза, ОС = &ВыбранноеОС) КАК МестонахождениеОССрезПоследних

В этом случае система сначала отберет записи по конкретному объекту, а затем найдет среди них последние по времени в разрезе оставшихся измерений.

Решение 3: Проблема несовпадения типов данных

Проанализируем ситуацию из практики (сообщение 31 в теме): иногда запрос возвращает пустой результат после добавления условий связи. Выясним причину. Часто в документах поле ИнвНомер является строкой, а в регистре сведений ИнвНомер — это ссылка на справочник ИнвентарныеНомера.

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


ПО БС_ПриходТоваровТаблицаТоваров.ИнвНомер = МестонахождениеОССрезПоследних.ИнвНомер.Код
// Или, если используется ПорядковыйНомер:
ПО БС_ПриходТоваровТаблицаТоваров.ИнвНомер = МестонахождениеОССрезПоследних.ИнвНомер.ПорядковыйНомер

Однако помните, что обращение через точку («разыменование ссылки») в условиях связи крайне негативно сказывается на производительности. Рекомендуем предварительно привести данные к одному типу во временных таблицах.

Решение 4: Получение последнего значения через МАКСИМУМ(Период)

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

  1. Создадим временную таблицу ВТ_ПоследниеДаты, где сгруппируем данные по ОС и выберем МАКСИМУМ(Период).
  2. Соединим эту временную таблицу с физической таблицей регистра (не виртуальной!) по полям ОС и Период.

Пример реализации этой логики:


ВЫБРАТЬ
    МестонахождениеОС.ОС КАК ОС,
    МАКСИМУМ(МестонахождениеОС.Период) КАК Период
ПОМЕСТИТЬ ВТ_ПоследниеДаты
ИЗ
    РегистрСведений.МестонахождениеОС КАК МестонахождениеОС
СГРУППИРОВАТЬ ПО
    МестонахождениеОС.ОС;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    РегистрМестонахождение.ОС,
    РегистрМестонахождение.Состояние
ИЗ
    ВТ_ПоследниеДаты КАК ВТ_Даты
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.МестонахождениеОС КАК РегистрМестонахождение
    ПО ВТ_Даты.ОС = РегистрМестонахождение.ОС
    И ВТ_Даты.Период = РегистрМестонахождение.Период

Этот метод гарантирует получение записи на самую последнюю дату, даже если в регистре присутствуют разные инвентарные номера или учреждения для одного объекта. Однако будьте осторожны: если на одну и ту же секунду (период) по одному объекту введено две разные записи, дублирование все равно может возникнуть (в этом случае стоит добавить в группировку поле НомерСтроки или использовать другие уникальные реквизиты).

Подведем итоги

Для корректной работы со СрезомПоследних мы должны:

Соблюдение этих правил позволит вашим отчетам и обработкам всегда выводить только актуальную и достоверную информацию.

← На главную