Сравнение таблиц значений (табличных частей)

06.12.13

Разработка - Математика и алгоритмы

Задача такова, сравнить 2 таблицы значений (Табличные части) и выдать результат, о том что в них изменилось, применительно к реальной задаче будет звучать так, показать пользователю что изменилось в документе.

Бесплатные

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Узнавайте о новых бесплатных решениях в нашей телеграм-группе Инфостарт БЕСПЛАТНО

Наименование Скачано Бесплатно
ПримерСравниванияТЗПоСтрокамСИспользованиемУдельногоВеса.epf
.epf 7,05Kb
56 Скачать бесплатно

Всем Привет!

Данная публикация в основном рассчитана на новичков, но надеюсь что и бывалые найдут что то полезное.

Собственно задача можно сказать несложная, но готовых вариантов я не увидел на просторах интернета.

Задача такова, сравнить 2 таблицы значений (Табличные части) и выдать результат, о том что в них изменилось, применительно к реальной задаче будет звучать так, показать пользователю что изменилось в документе. Допустим пусть это будут 2 разные версии объектов записанные в ИБ, конечно многие могут сказать (или подумать) может быть научить пользователя пользоваться обработкой История изменений объектов. Всё конечно хорошо в теории, но История изменения объектов (допустим УПП 1.3.38.3) обладает рядом недостатков, а именно:

  1. При версии объекта больше 999 при работе вызывает ошибку, оно и понятно разработчики не позаботились о корректном переводе (Строка – Число и обратно), но да бог с ними, не об этом речь.
  2. Обработка сравнивает табличные части по индексам, т.е. если строка будет перемещена с 1-й на 3-ю позицию, обработка покажет изменения, а они были? Тоже думаю что нет.

Накидал небольшой кусочек кода, как выкрутится из такой ситуации.

  1. Дано:

Таблица значений эталон, с ней будем сравнивать.

 

 

Таблица значений, которую  будем сравнивать.

 

Колонки «ВесСтроки, Идентификатор,БылВыбран» были добавлены для успешного анализа.

 2. Думаю описывать заполнение таблиц нет смысла, они должны у нас уже быть по задаче, отмечу только что для успешной обработки нам понадобится дополнительная структура «СтруктураВеса».

Дело в том что, при таком подходе мы сможем более  гибко настроить алгоритм для соответствия строк.

 

Возьмём пример из таблиц Выше

Строка Номер 2 в обоих таблицах содержит всего 1 изменение , а если их будет 2 и более ?

Ответ прост, при таком подходе мы можем легко настроить алгоритм так, что при совпадении только по номенклатуре  строки сопоставятся или нет, а если изменят только номенклатуру и остальные значения в строке будут нетронутыми сопоставлять ли такие строки или нет? Именно за этим мы и делаем табличку с весом значимости колонки.

 3. Так же нам понадобится таблица куда мы будем записывать результат работы алгоритма, рисунок уже после отработки алгоритма.

 

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

 

Собственно весь код ниже, так же выкладываю обработку с примером.


Функция ПровестиАнализ(ТЗИсточник,ТЗПриемник,ТЗАнализ,МассивКолонок,СтруктураВеса)

    Для Каждого Строка из ТЗИсточник Цикл
       
МаксимальныйПорог   = СтруктураВеса.Количество() + 1;
       
МинимальныйПорог    = 3;
       
ТЗПриемник.ЗаполнитьЗначения(0,"ВесСтроки");
        Для Каждого
СтрокаПоиска из ТЗПриемник Цикл
            Если
СтрокаПоиска.БылВыбран Тогда
                Продолжить;
            КонецЕсли;
           
ВесСтроки = 0;
            Для каждого
Колонка Из МассивКолонок Цикл
               
ЗначениеИсточник = Строка[Колонка];
               
ЗначениеПриемник = СтрокаПоиска[Колонка];
                Если
СтруктураВеса.Свойство(Колонка) Тогда
                    
Вес = СтруктураВеса[Колонка];
                Иначе
                     Продолжить;
                КонецЕсли;
                Если
ЗначениеИсточник = ЗначениеПриемник Тогда
                   
ВесСтроки = ВесСтроки + Вес;
                КонецЕсли;
            КонецЦикла;
           
СтрокаПоиска.ВесСтроки = ВесСтроки;
        КонецЦикла;

       
ТЗПриемник.Сортировать("ВесСтроки Убыв, БылВыбран Убыв");

        Для Каждого
СтрокаПоиска из ТЗПриемник Цикл
            Если
СтрокаПоиска.БылВыбран Тогда
                Продолжить;
            КонецЕсли;

            Если СтрокаПоиска.ВесСтроки = МаксимальныйПорог Тогда
                СтрокаПоиска.БылВыбран = Истина;
               
НоваяСтрока = ТЗАнализ.Добавить();
               
НоваяСтрока.ИдентификаторИсточник = СтрокаПоиска.Идентификатор;
               
НоваяСтрока.ИдентификаторПриемник = Строка.Идентификатор;
               
НоваяСтрока.Состояние = "Совпадение";
                Прервать;
            ИначеЕсли
СтрокаПоиска.ВесСтроки >= МинимальныйПорог Тогда
               
СтрокаПоиска.БылВыбран = Истина;
               
НоваяСтрока = ТЗАнализ.Добавить();
               
НоваяСтрока.ИдентификаторИсточник = СтрокаПоиска.Идентификатор;
               
НоваяСтрока.ИдентификаторПриемник = Строка.Идентификатор;
               
НоваяСтрока.Состояние = "Изменен";
                Прервать;
            ИначеЕсли
СтрокаПоиска.ВесСтроки < МинимальныйПорог Тогда
               
НоваяСтрока = ТЗАнализ.Добавить();
               
НоваяСтрока.ИдентификаторИсточник = СтрокаПоиска.Идентификатор;
               
НоваяСтрока.Состояние = "Удален";
                Прервать;
            КонецЕсли;
        КонецЦикла;
    КонецЦикла;

   
Отбор = Новый Структура;
   
Отбор.Вставить("БылВыбран", Ложь);
   
НайденныеСтроки = ТЗПриемник.НайтиСтроки(Отбор);

    Для Каждого
НайденнаяСтрока из НайденныеСтроки Цикл
       
СтрокаПоиска.БылВыбран = Истина;
       
НоваяСтрока = ТЗАнализ.Добавить();
       
НоваяСтрока.ИдентификаторПриемник = НайденнаяСтрока.Идентификатор;
       
НоваяСтрока.Состояние = "Добавлен";
    КонецЦикла;

    Возврат
ТЗАнализ;

КонецФункции
// ПровестиАнализ(ТЗИсточник,ТЗПриемник,ТЗАнализ)
 

Надеюсь статья была полезной.

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

См. также

SALE! %

Мастера заполнения Поиск данных База данных Инструментарий разработчика Корректировка данных Универсальные функции Механизмы платформы 1С Подбор и обработка объектов 1С 8.3 1С 8.5 Платные (руб)

Infostart MagicInput улучшает подбор в полях ввода 1С: ищет по любой части названия и по нескольким ключевым фрагментам, распознаёт ввод в другой раскладке и показывает иконки/статусы объектов прямо в списке. Поддерживает вставку навигационной ссылки/представления документа для автоподбора; для разработчиков доступны поиск по GUID и полному имени предопределённого. Работает в управляемых формах и подключается в большинстве конфигураций 1С 8.3/8.5.

5000 4000 руб.

25.02.2026    1590    9    1    

11

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

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

21.05.2024    53797    dimanich70    84    

174

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

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    24843    YA_418728146    8    

174

Пакетная печать Печатные формы Адаптация типовых решений Универсальные функции 1С:Предприятие 8 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Абонемент ($m)

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

2 стартмани

22.08.2023    8618    116    progmaster    23    

6

Инструментарий разработчика Универсальные функции 1С:Предприятие 8 1С:Бухгалтерия 3.0 1С:ERP Управление предприятием 2 1С:Управление холдингом 1С:Зарплата и Управление Персоналом 3.x 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Управление торговлей 11 1С:Розница 2 1С:Розница 3.0 1С:Документооборот Абонемент ($m)

Копирует в буфер значения из списков, из ячеек отчетов, таблиц, настроек списков, других отборов и вставляет в выбранную настройку отбора. Работает с Объект не найден. Работает как в одной так и между разными базами 1С. Использует комбинации [Alt+C] Копировать список, [Alt+V] Вставить список. Также для копирования данных используется стандартная [Ctrl+C] (например из открытого xls, mxl, doc и т.п. файла скопировать список наименований)

1 стартмани

13.10.2022    25498    239    sapervodichka    118    

141

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

В данном материале рассмотрим типовой алгоритм подсистемы контроля учета БСП в конфигурациях на примерах.

18.07.2022    10589    quazare    8    

114

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

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

28.05.2022    13598    milkers    11    

100
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. kwazi 787 07.12.13 12:56 Сейчас в теме
в бсп есть подсистема версионирование и есть отчет по сравнению версий там уже все есть
2. echo77 1938 07.12.13 19:28 Сейчас в теме
(1) Автор пишет о существовании нескольких багов этого отчета.
Я бы взял этот отчет за основу и допилил
3. Xatori111 18 07.12.13 22:11 Сейчас в теме
(2)Это всего лишь пример как можно сравнить таблицы, а отчёт допилить не проблема, вопрос надо ли?
Дмитрий74Чел; +1 Ответить
4. Yashazz 4901 08.12.13 12:07 Сейчас в теме
1. Таких сравнивалок для таблиц значений уже было вагон, и я не понимаю, почему авторы почти всех их делают НЕ через запрос.
2. Если делать не для себя, а для пользователя, то я бы предложил игры с самим интерфейсом документа (например, изменить фон нужных полей и ячеек табчастей другим цветом, для изменившихся/добавленных итд, вопрос только про удалённые).
5. Поручик 4607 09.12.13 07:58 Сейчас в теме
(4) Сделай через запрос, оценим поделие.
Evil Beaver; +1 Ответить
6. Yashazz 4901 09.12.13 23:23 Сейчас в теме
(5) Изволите желать через СКД, да с наборами, аль бо по-простому, в обычном запросе? )))
7. Поручик 4607 09.12.13 23:55 Сейчас в теме
(6) Сделайте весь список, пожалуйста. Я бы не отказался посмотреть на СКД с наборами
8. soap 67 11.12.13 15:14 Сейчас в теме
Для обычного запроса как то так простейший пример

ТЗ1=Новый ТаблицаЗначений ;
ТЗ2=Новый ТаблицаЗначений;
ТЗ1.Колонки.Добавить("П1");
ТЗ1.Колонки.Добавить("П2");
ТЗ1.Колонки.Добавить("П3");
ТЗ2.Колонки.Добавить("П1");
ТЗ2.Колонки.Добавить("П2");
ТЗ2.Колонки.Добавить("П3");

Запрос.Текст =
"ВЫБРАТЬ
| ЕСТЬNULL(ТЗ1.П1,ТЗ2.П1) КАК П1,
| ЕСТЬNULL(ТЗ1.П1,1) КАК Удалено,
| ЕСТЬNULL(ТЗ2.П1,2) КАК Добавлено,
| ТЗ1.П2 КАК П2_Начальное ,
| ТЗ2.П2 КАК П2_Текущее ,
| ТЗ1.П3 КАК П3_Начальное ,
| ТЗ2.П3 КАК П3_Текущее,
| ВЫБОР
| Когда ТЗ1.П2<>ТЗ2.П2
| Тогда 3
| ИНАЧЕ 4
| КОНЕЦ КАК ИзмененоП2,
| ВЫБОР
| Когда ТЗ1.П3<>ТЗ2.П3
| Тогда 3
| ИНАЧЕ 4
| КОНЕЦ КАК ИзмененоП3
| ИЗ
| ТЗ1 КАК ТЗ1
| ПОЛНОЕ СОЕДИНЕНИЕ ТЗ2 КАК ТЗ2
| ПО ТЗ2.П1=ТЗ2.П1";
9. amyd 93 12.12.13 10:03 Сейчас в теме
тоже самое, но на основе запросов, все же перебирать табличные части, пускай и в цикле, "мовитон", особенно если ТЗ за 5000 записей.
сначала хотел вывести "контр публикацию" с ссылкой на эту, но уж очень хорошо расписана, поэтому просто дополню в комментарии своей процедурой сравнения на основе запросов
функция ТабличныеЧастиРазныеУлучшенная(ТаблицаДо,ТаблицаПосле,ТаблицаРасхождений=неопределено) экспорт
	//ТаблицаДо=док.Товары.Выгрузить();
	//	ТаблицаПосле=док.Товары.Выгрузить();
	ТекстЗапроса="Выбрать ";	
	
	для каждого эл из ТаблицаДо.Колонки цикл
		если эл.Имя="КлючСтроки" тогда
			продолжить;
		конецесли;
		ТекстЗапроса = ТекстЗапроса +"
		| ТТДо."+эл.Имя+",";
	конеццикла;
	ТекстЗапроса=Лев(ТекстЗапроса,стрдлина(ТекстЗапроса)-1);
	ТекстЗапроса = ТекстЗапроса+"
	|поместить ТаблоДо 
	|из 
	|	&ТабДо как ТТДо
	|;	
	|Выбрать";
	для каждого эл из ТаблицаДо.Колонки цикл
		если эл.Имя="КлючСтроки" тогда
			продолжить;
		конецесли;
		
		ТекстЗапроса = ТекстЗапроса +"
		| ТТПосле."+эл.Имя+",";
	конеццикла;
	ТекстЗапроса=Лев(ТекстЗапроса,стрдлина(ТекстЗапроса)-1);	
	ТекстЗапроса = ТекстЗапроса+"
	|поместить ТаблоПосле 
	|из 
	|	&ТабПосле как ТТПосле
	|;
	|выбрать" ;
	для каждого эл из ТаблицаДо.Колонки цикл
		если эл.Имя="КлючСтроки" тогда
			продолжить;
		конецесли;
		
		ТекстЗапроса = ТекстЗапроса +"
		| Сборочный."+эл.Имя+",";
	конеццикла;
	ТекстЗапроса = ТекстЗапроса+"
	| ЕстьNULL(сумма(Сборочный.Контроль),0) как Контроль
	|из 
	|	(
	|выбрать " ;
	для каждого эл из ТаблицаДо.Колонки цикл
		если эл.Имя="КлючСтроки" тогда
			продолжить;
		конецесли;
		
		ТекстЗапроса = ТекстЗапроса +"
		| ТаблоДо."+эл.Имя+",";
	конеццикла;
	ТекстЗапроса = ТекстЗапроса+"
	|   -1 как Контроль
	| из  ТаблоДо как ТаблоДо
	|	 
	|Объединить все
	|
	| Выбрать ";
	для каждого эл из ТаблицаДо.Колонки цикл
		если эл.Имя="КлючСтроки" тогда
			продолжить;
		конецесли;
		
		ТекстЗапроса = ТекстЗапроса +"
		| ТаблоПосле."+эл.Имя+",";
	конеццикла;
	ТекстЗапроса = ТекстЗапроса+"
	|   1
	| из  ТаблоПосле как ТаблоПосле
	| ) как Сборочный
	| сгруппировать по";
	для каждого эл из ТаблицаДо.Колонки цикл
		если эл.Имя="КлючСтроки" тогда
			продолжить;
		конецесли;
		
		ТекстЗапроса = ТекстЗапроса +"
		| Сборочный."+эл.Имя+",";
	конеццикла;
	ТекстЗапроса=Лев(ТекстЗапроса,стрдлина(ТекстЗапроса)-1);	
	
	запр = новый Запрос(ТекстЗапроса);
	
	Запр.УстановитьПараметр("ТабДо",ТаблицаДо);
	Запр.УстановитьПараметр("ТабПосле",ТаблицаПосле);
	
	ВЫЗаДН = запр.Выполнить().Выгрузить();
	ТаблицаРасхождений=ВЫЗаДН.Скопировать();
	если ВЫЗаДН.найти(1,"контроль")<> неопределено или ВЫЗаДН.найти(-1,"контроль")<>неопределено тогда
		возврат истина;
	иначе
		возврат ложь;
	конецесли;
	
	
конецфункции	
Показать
Для отправки сообщения требуется регистрация/авторизация