При работе с периодическими регистрами сведений часто возникает задача удаления самой актуальной (последней) записи по определенному набору измерений. Типичный пример: отмена последнего изменения цены номенклатуры, курса валюты или статуса документа. Сложность заключается в том, что для удаления конкретной записи нам необходимо знать её точный период, который не всегда совпадает с текущей датой.
В этой статье мы подробно разберем, как правильно вычислить последнюю запись и какими методами платформы 1С её можно удалить. Мы проанализируем использование менеджера записи, набора записей и оптимизацию через запросы.
Самый простой и интуитивно понятный способ — это сначала определить дату последней записи, а затем использовать РегистрСведенийМенеджерЗаписи для её удаления. Рассмотрим этот процесс по шагам.
Для начала нам нужно получить данные последней записи. Для этого идеально подходит метод СрезПоследних. Проанализируем ситуацию: если мы просто передадим в менеджер записи текущую дату, он попытается найти запись, созданную именно в эту секунду (или день, в зависимости от периодичности). Если запись была создана вчера, менеджер её «не увидит».
Шаг 1. Получаем период последней записи
Воспользуемся методом СрезПоследних, передав в него структуру отбора по интересующим нас измерениям.
// Определяем отбор по измерениям
Отбор = Новый Структура;
Отбор.Вставить("ВладелецСчета", ВладелецСчета);
Отбор.Вставить("БанковскийСчет", БанковскийСчет);
// Получаем таблицу с последней записью
ТаблицаПоследнейЗаписи = РегистрыСведений.МойРегистр.СрезПоследних(ТекущаяДата(), Отбор);
Если ТаблицаПоследнейЗаписи.Количество() > 0 Тогда
// Получаем точный период из найденной записи
НужныйПериод = ТаблицаПоследнейЗаписи[0].Период;
Иначе
Возврат; // Записей нет, удалять нечего
КонецЕсли;
Шаг 2. Удаление записи через Менеджер записи
Теперь, когда у нас есть точный Период, мы можем инициализировать менеджер записи, заполнить все ключевые поля и вызвать метод Удалить().
МЗ = РегистрыСведений.МойРегистр.СоздатьМенеджерЗаписи();
МЗ.ВладелецСчета = ВладелецСчета;
МЗ.БанковскийСчет = БанковскийСчет;
МЗ.Период = НужныйПериод;
// Перед удалением рекомендуется прочитать запись, чтобы убедиться в её существовании
МЗ.Прочитать();
Если МЗ.Выбран() Тогда
МЗ.Удалить();
КонецЕсли;
Важное замечание: Для успешной работы метода Прочитать() и последующего удаления необходимо заполнить все измерения, которые входят в состав уникального ключа регистра. Если вы пропустите хотя бы одно измерение, менеджер записи не сможет идентифицировать строку в базе данных.
Использование объекта НаборЗаписей считается более «профессиональным» подходом, так как он работает быстрее при массовых операциях и позволяет избежать лишнего вызова Прочитать(). Выясним причину: набор записей позволяет наложить фильтр и просто перезаписать пустой набор, что фактически удаляет данные.
Рассмотрим пример реализации:
Набор = РегистрыСведений.МойРегистр.СоздатьНаборЗаписей();
// Устанавливаем фильтры (отборы) по измерениям и периоду
Набор.Отбор.ВладелецСчета.Установить(ВладелецСчета);
Набор.Отбор.БанковскийСчет.Установить(БанковскийСчет);
Набор.Отбор.Период.Установить(НужныйПериод);
// Записываем пустой набор с флагом замещения
// Это удалит все записи, попадающие под фильтр
Набор.Записать(Истина);
Преимущество этого метода в том, что если по какой-то причине (например, сбой при программном заполнении) в одну и ту же секунду/день попало несколько идентичных по измерениям записей, набор записей гарантированно очистит их все.
Метод СрезПоследних удобен, но на больших объемах данных он может работать медленно, так как вычисляет виртуальную таблицу и выбирает все ресурсы. Если нам нужно только узнать дату последней записи, эффективнее использовать прямой запрос к основной таблице регистра.
Проанализируем пример запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| МАКСИМУМ(МойРегистр.Период) КАК ПоследнийПериод
|ИЗ
| РегистрСведений.МойРегистр КАК МойРегистр
|ГДЕ
| МойРегистр.ВладелецСчета = &ВладелецСчета
| И МойРегистр.БанковскийСчет = &БанковскийСчет";
Запрос.УстановитьПараметр("ВладелецСчета", ВладелецСчета);
Запрос.УстановитьПараметр("БанковскийСчет", БанковскийСчет);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Если Выборка.Следующий() И ЗначениеЗаполнено(Выборка.ПоследнийПериод) Тогда
// Теперь используем Выборка.ПоследнийПериод для удаления через МенеджерЗаписи
КонецЕсли;
Использование функции МАКСИМУМ(Период) в запросе — это самый быстрый способ получить дату последней активности в системе по конкретному объекту.
При решении задачи удаления записей необходимо учитывать два критических момента:
День, то время в поле Период всегда будет равно 00:00:00. Если же установлена периодичность Секунда, то при поиске и удалении крайне важно соблюдать точность до секунды. Ошибка в 1 секунду приведет к тому, что метод Прочитать() вернет ложь.
НачатьТранзакцию();
Попытка
// Здесь код поиска периода и удаления
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ЗаписьЖурналаРегистрации("УдалениеЗаписи", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
КонецПопытки;
Подводя итог, можно сказать, что правильный алгоритм удаления последней записи всегда состоит из двух фаз: точная идентификация периода (через срез последних или запрос) и адресное удаление (через менеджер записи или набор с фильтром по периоду).