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

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

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

Разбор основной проблемы: Почему СрезПоследних возвращает «лишнее»

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

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


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

Выясним причину дублей: автор обращается не к самому документу Документ.ЗаявкаНаРасходованиеСредств, а к его табличной части РасшифровкаПлатежа. Если в одной заявке заполнено пять строк расшифровки, то при левом соединении со срезом последних система выведет состояние пять раз — по одному разу для каждой строки табличной части. Это создает иллюзию того, что срез последних работает неправильно, хотя на самом деле проблема в соединении с детализированной таблицей.

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

Виртуальная таблица СрезПоследних — это не просто выборка. Это мощный механизм, который принимает параметры. Рассмотрим их подробнее:

  1. Период: Указывает момент времени, на который нужно получить данные. Если параметр не задан, 1С берет самые свежие данные на текущий момент (условно — на «бесконечность»).
  2. Условие: Позволяет отфильтровать данные еще на этапе формирования виртуальной таблицы на стороне SQL-сервера.

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


// Неправильно (низкая производительность)
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СостоянияСогласованияЗаявок.СрезПоследних() КАК Срез
ПО Заявка = Срез.Заявка
ГДЕ Заявка = &НужнаяЗаявка

// Правильно (высокая производительность)
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СостоянияСогласованияЗаявок.СрезПоследних(&Период, Заявка = &НужнаяЗаявка) КАК Срез
ПО Заявка = Срез.Заявка

Влияние измерений регистра на результат

Важно помнить: СрезПоследних возвращает последнюю запись в разрезе уникальных комбинаций измерений. Если в вашем регистре «Состояния согласования заявок» кроме измерения Заявка есть, например, измерение Ответственный, то запрос вернет последнюю запись для каждого ответственного по этой заявке.

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


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

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

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

Решение для непериодических регистров

Если ваш регистр сведений является непериодическим, у него нет виртуальной таблицы СрезПоследних. В этом случае «последнюю» запись определяют по какому-либо реквизиту (например, ДатаИзменения или ПорядковыйНомер).

Разберем, как получить такие данные. Мы можем применить функцию МАКСИМУМ к нашему критерию «свежести». Рассмотрим пример, где мы ищем запись с максимальной датой:


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

Этот подход с коррелированным подзапросом удобен для небольших выборок, но на больших объемах данных лучше использовать временные таблицы с группировкой по МАКСИМУМ(Дата), как было показано в предыдущем примере.

Подведем итоги и сформируем алгоритм действий

Чтобы ваш отчет или обработка всегда показывали корректное «последнее» состояние и не дублировали строки, придерживайтесь следующих шагов:

  1. Проверьте источник данных: Если вы соединяете статус со ссылкой на документ, используйте основную таблицу документа (Документ.Название), а не его табличную часть. Если табличная часть необходима (нужны суммы по строкам), сгруппируйте результат по ссылке документа в конце запроса или предварительно получите статусы во временную таблицу.
  2. Всегда передавайте параметры в СрезПоследних: Обязательно указывайте дату (&Период) и, если возможно, массив ссылок на объекты. Это значительно ускорит работу SQL-сервера.
  3. Анализируйте измерения: Убедитесь, что в регистре нет «лишних» измерений, которые заставляют СрезПоследних возвращать несколько строк на один объект.
  4. Используйте Временные Таблицы: Для сложных отчетов сначала получите список уникальных ссылок (Заявок), затем для них получите статусы из СрезПоследних, сохраните это во временную таблицу и только потом соединяйте с суммами и аналитикой.

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

← На главную