Как получить срез первых записей из таблицы изменений плана обмена в 1С?

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

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

Постановка задачи и анализ структуры данных

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

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

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

Разберем самый простой вариант, предложенный в обсуждении. Если нам нужно просто найти идентификатор самого раннего изменения в рамках узла плана обмена, мы можем использовать агрегатную функцию МИНИМУМ. Проанализируем пример кода:


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

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

Решение 2: Получение полных данных (ресурсов) для первой записи

Рассмотрим более сложный и правильный с точки зрения архитектуры 1С подход. Чтобы получить полноценный «срез первых» из изменений, нам нужно выполнить соединение. Разберем по шагам:

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

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


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

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

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

Решение 3: Группировка "одна запись в день"

Иногда ТЗ требует, чтобы в целевой регистр попадала только одна запись за конкретные сутки, даже если изменений было несколько. В этом случае мы воспользуемся функцией НАЧАЛОПЕРИОДА. Выясним, как изменится наш запрос:


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

Этот подход гарантирует нам получение самой первой хронологической записи в рамках каждого дня для каждого сотрудника.

Особенности работы с удаленными записями

Проанализируем ситуацию, которая часто ставит в тупик начинающих разработчиков: в основной таблице регистра запись удалена, но в таблице изменений она всё еще присутствует (ожидает обработки). При выполнении ВНУТРЕННЕЕ СОЕДИНЕНИЕ с основной таблицей регистра такая запись просто исчезнет из выборки. Если ваша задача — отразить в другом регистре факт удаления, используйте ЛЕВОЕ СОЕДИНЕНИЕ и проверяйте ресурсы на NULL.

Оптимизация и завершение обработки

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

Для удаления регистрации воспользуемся методом ПланыОбмена.УдалитьРегистрациюИзменений(). Рассмотрим пример кода на языке 1С:


// Предположим, РезультатЗапроса содержит колонку Сотрудник и Период
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
    // Создаем отбор для удаления регистрации
    Отбор = Новый Структура;
    Отбор.Вставить("Сотрудник", Выборка.Сотрудник);
    Отбор.Вставить("Период", Выборка.Период);
    
    ПланыОбмена.УдалитьРегистрациюИзменений(УзелОбмена, Метаданные.РегистрыСведений.Начисления, Отбор);
КонецЦикла;

Важное предостережение: использование УдалитьРегистрациюИзменений в цикле по одной записи может быть неэффективным при больших объемах данных. В таких случаях лучше формировать массив наборов записей или удалять регистрацию целиком по узлу, если вы уверены, что обработали абсолютно все изменения.

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

← На главную