История данных. Отбор по незначащим реквизитам

17.04.26

Разработка - Универсальные функции

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

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

Информация на сайте ИТС довольно скудная, хочу поделиться опытом.

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

Функция СписокМетаданныхДляОбхода()
	ТЗ = Новый ТаблицаЗначений;
	ТЗ.Колонки.Добавить("ИмяОбъектаМетаданных");
	ТЗ.Колонки.Добавить("ИмяОбъектаДляЗапроса"); 

	НоваяСтрока = ТЗ.Добавить();
	НоваяСтрока.ИмяОбъектаМетаданных = "ПланыОбмена";
	НоваяСтрока.ИмяОбъектаДляЗапроса = "ПланОбмена";
	
	НоваяСтрока = ТЗ.Добавить();
	НоваяСтрока.ИмяОбъектаМетаданных = "Константы";
	НоваяСтрока.ИмяОбъектаДляЗапроса = "Константа";
	
	НоваяСтрока = ТЗ.Добавить();
	НоваяСтрока.ИмяОбъектаМетаданных = "Справочники";
	НоваяСтрока.ИмяОбъектаДляЗапроса = "Справочник";
	
	НоваяСтрока = ТЗ.Добавить();
	НоваяСтрока.ИмяОбъектаМетаданных = "Документы";
	НоваяСтрока.ИмяОбъектаДляЗапроса = "Документ";
	
	НоваяСтрока = ТЗ.Добавить();
	НоваяСтрока.ИмяОбъектаМетаданных = "ПланыВидовХарактеристик";
	НоваяСтрока.ИмяОбъектаДляЗапроса = "ПланВидовХарактеристик";
	
	НоваяСтрока = ТЗ.Добавить();
	НоваяСтрока.ИмяОбъектаМетаданных = "ПланыСчетов";
	НоваяСтрока.ИмяОбъектаДляЗапроса = "ПланСчетов";
	
	НоваяСтрока = ТЗ.Добавить();
	НоваяСтрока.ИмяОбъектаМетаданных = "ПланыВидовРасчета";
	НоваяСтрока.ИмяОбъектаДляЗапроса = "ПланВидовРасчета";
	
	НоваяСтрока = ТЗ.Добавить();
	НоваяСтрока.ИмяОбъектаМетаданных = "РегистрыСведений";
	НоваяСтрока.ИмяОбъектаДляЗапроса = "РегистрСведений";
	
	НоваяСтрока = ТЗ.Добавить();
	НоваяСтрока.ИмяОбъектаМетаданных = "БизнесПроцессы";
	НоваяСтрока.ИмяОбъектаДляЗапроса = "БизнесПроцесс";
	
	НоваяСтрока = ТЗ.Добавить();
	НоваяСтрока.ИмяОбъектаМетаданных = "Задачи";
	НоваяСтрока.ИмяОбъектаДляЗапроса = "Задача";
	
	Возврат ТЗ;
КонецФункции

После получения массива, можем получить объекты метаданных, в которых включено использование истории:

Функция СписокОбъектовИспользующихИсторию() 
	СписокМетаданных = СписокМетаданныхДляОбхода();
	
	Для Каждого СтрокаТаблицы Из СписокМетаданных Цикл  		
		Для Каждого ОбМетаданных Из Метаданные[СтрокаТаблицы.ИмяОбъектаМетаданных] Цикл
			МассивОбъектов = Новый Массив;
			Если ОбМетаданных.ИсторияДанных = Метаданные.СвойстваОбъектов.ИспользованиеИсторииДанных.Использовать Тогда
				МассивОбъектов.Добавить(ОбМетаданных);	   
			КонецЕсли;
		КонецЦикла; 
		СтрокаТаблицы.МассивОбъектов = МассивОбъектов;  
	КонецЦикла;
	
	Возврат СписокМетаданных;
КонецФункции

А теперь подводный камень.

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

Создадим функцию, которая возвращает массив полей для отбора по истории изменений:

Функция МассивИменПолей(ОбъектМетаданных, ТипОбъектаМетаданных)
	
	ИзмененияПолей = Новый Массив;
	Если ТипОбъектаМетаданных = "Документы" или ТипОбъектаМетаданных = "Справочники" Тогда
		Для Каждого Реквизит Из ОбъектМетаданных.Реквизиты Цикл
			Если Реквизит.Имя = "Комментарий" Тогда
				Продолжить;
			КонецЕсли;   
			Если Реквизит.Имя = "Ответственный" Тогда
				Продолжить;
			КонецЕсли;    
			ИзмененияПолей.Добавить(Реквизит.Имя);	
		КонецЦикла;  
		Для Каждого ТЧ Из ОбъектМетаданных.ТабличныеЧасти Цикл  
			Для Каждого РеквизитТЧ Из ТЧ.Реквизиты Цикл
				ИзмененияПолей.Добавить(ТЧ.Имя + "." + РеквизитТЧ.Имя);	
			КонецЦикла;
		КонецЦикла;   
		Для Каждого Реквизит Из ОбъектМетаданных.СтандартныеРеквизиты Цикл 
			Если Реквизит.Имя = "Ссылка" Тогда
				Продолжить;
			КонецЕсли; 
			ИзмененияПолей.Добавить(Реквизит.Имя);
		КонецЦикла;
	КонецЕсли;
	Возврат ИзмененияПолей;   
	
КонецФункции

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

Далее получаем версии с отбором:

Отбор = Новый Структура; // создаем структуру для отбора
Отбор.Вставить("Метаданные", Элемент.Метаданные); // добавляем в него метаданные из массива, полученного ранее
ТЗВерсий = ИсторияДанных.ВыбратьВерсии(Отбор);  // выбираем версии без отбора по измененным полям
Отбор.Вставить("ИзменениеЗначенийПолей", МассивИменПолей()); // с таким массивом история версий вернет только те версии, в которых изменялись ВСЕ реквизиты из массива
ТЗВерсий = ИсторияДанных.ВыбратьВерсии(Отбор); // Здесь вернется в лучшем случае одна версия(или версия, где менялись ВСЕ реквизиты). Или ни одной, если какой-то реквизит был добавлен в конфигурацию после добавления объекта в базу

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

МассивНенужныхПолей1 = Новый Массив;
МассивНенужныхПолей.Добавить("НеотслеживамоеПоле1");   
		
МассивНенужныхПолей2= Новый Массив;
МассивНенужныхПолей2.Добавить("НеотслеживамоеПоле2"); 
		
МассивДвухНенужныхПолей = Новый Массив; //если два неотслеживаемых поля изменены в одной версии
МассивДвухНенужныхПолей.Добавить("НеотслеживамоеПоле2");
МассивДвухНенужныхПолей.Добавить("НеотслеживамоеПоле3");
		
Отбор = Новый Структура;
Отбор.Вставить("Метаданные", Элемент.Метаданные);
Отбор.Вставить("ИзменениеЗначенийПолей", МассивНенужныхПолей1);
ТЗВерсий1 = ИсторияДанных.ВыбратьВерсии(Отбор);
ВерсииКУдалению = Новый Массив;
Для Каждого СтрокаВерсии Из ТЗВерсий1 Цикл    
	Если СтрокаВерсии.НомерВерсии = 1 Тогда Продолжить; КонецЕсли;
	РазличиеВерсий = ИсторияДанных.ПолучитьРазличияВерсий(СтрокаВерсии.Данные, СтрокаВерсии.НомерВерсии, СтрокаВерсии.НомерВерсии-1);
	Если РазличиеВерсий.Количество() = 1 Тогда  
		ВерсииКУдалению.Добавить(Новый Структура("Данные, НомерВерсии", СтрокаВерсии.Данные, СтрокаВерсии.НомерВерсии));
	КонецЕсли;
КонецЦикла;  
		
Отбор.Вставить("ИзменениеЗначенийПолей", МассивНенужныхПолей2);
ТЗВерсий2 = ИсторияДанных.ВыбратьВерсии(Отбор);
Для Каждого СтрокаВерсии Из ТЗВерсий2 Цикл    
	Если СтрокаВерсии.НомерВерсии = 1 Тогда Продолжить; КонецЕсли;
		РазличиеВерсий = ИсторияДанных.ПолучитьРазличияВерсий(СтрокаВерсии.Данные, СтрокаВерсии.НомерВерсии, СтрокаВерсии.НомерВерсии-1);
		Если РазличиеВерсий.Количество() = 1 Тогда  
			ВерсииКУдалению.Добавить(Новый Структура("Данные, НомерВерсии", СтрокаВерсии.Данные, СтрокаВерсии.НомерВерсии));
		КонецЕсли;
КонецЦикла;
		
Отбор.Вставить("ИзменениеЗначенийПолей", МассивДвухНенужныхПолей);
ТЗВерсийПоДвумПолям = ИсторияДанных.ВыбратьВерсии(Отбор);
	Для Каждого СтрокаВерсии Из ТЗВерсийПоДвумПолям Цикл    
		Если СтрокаВерсии.НомерВерсии = 1 Тогда Продолжить; КонецЕсли;
		РазличиеВерсий = ИсторияДанных.ПолучитьРазличияВерсий(СтрокаВерсии.Данные, СтрокаВерсии.НомерВерсии, СтрокаВерсии.НомерВерсии-1);
		Если РазличиеВерсий.Количество() = 2 Тогда  
			ВерсииКУдалению.Добавить(Новый Структура("Данные, НомерВерсии", СтрокаВерсии.Данные, СтрокаВерсии.НомерВерсии));
		КонецЕсли;
	КонецЦикла;
		
Для Каждого ЛишнняяВерсия Из ВерсииКУдалению Цикл
	СтрокаВерсииКУдалению = ТЗВерсий.НайтиСтроки(ЛишнняяВерсия);		
	ТЗВерсий.Удалить(СтрокаВерсииКУдалению[0]);
КонецЦикла;

Надеюсь, эта информация будет кому-то полезна.

Вступайте в нашу телеграмм-группу Инфостарт

ИсторияДанных ИзменениеЗначенийПолей отбор по истории данных обработка истории данных

См. также

Загрузка и выгрузка в Excel Универсальные функции Программист 1С:Предприятие 8 Россия Бесплатно (free)

Описанный ниже подход позволяет в три шага заполнять формулы в Excel файлы, вне зависимости от ОС сервера (MS Windows Server или Linux). Подход подразумевает отказ от работы с COM-объектом в пользу работы через "объектную модель документа" (DOM).

30.10.2025    4636    Abysswalker    11    

46

Универсальные функции Работа с интерфейсом Программист 1С:Предприятие 8 Бесплатно (free)

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

14.05.2025    8609    DeerCven    15    

62

Универсальные функции Программист 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

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

21.05.2024    56509    dimanich70    85    

174

Универсальные функции Программист 1С:Предприятие 8 1C:Бухгалтерия Абонемент ($m)

Задача: вставить картинку из буфера обмена на форму средствами платформы 1С.

1 стартмани

18.03.2024    7957    7    John_d    13    

59

Универсальные функции Программист Стажер 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Пришлось помучиться с GUID-ами немного, решил поделиться опытом, мало ли кому пригодится.

12.02.2024    71003    atdonya    31    

72

Универсальные функции Программист 1С:Предприятие 8 Бесплатно (free)

На заключительных этапах, когда идет отладка или доработка интерфейса, необходимо много раз переоткрыть внешний объект. Вот один из способов автоматизации этого.

30.11.2023    9966    ke.92@mail.ru    17    

68
Для отправки сообщения требуется регистрация/авторизация