Книга знаний

Рекламное место пустует
1С:Предприятие / v8

v8: Сравнение двух таблиц значений с ключемыми полями

Иногда нужно сравнить таблицы значений, у которых одинаковые ключевые поля, например срез с регистра сведений, с целью определения, какие изменения произошли - какие записи были добавлены, удалены, изменены. Я придумал достаточно быстрый алгоритм для такой проверки - всего лишь одна свертка.Автор статьи: Гений 1С | Редакторы:
Последняя редакция №3 от 03.07.09 | История
URL: http://kb.mista.ru/article.php?id=441

Ключевые слова: алгоритм,таблица значений,сравнение


Задача формулировалась так (http://www.forum.mista.ru/topic.php?&id=245242#F):

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

Итак, в одной таблице значений есть колонки:
Изм1, Изм2,...ИзмН   Рес1, ...РесМ
Это начальное состояние регистра сведений.

В другой таблице значений такие же колонки:
Изм1, Изм2,...ИзмН   Рес1, ...РесМ
Это конечное состояние регистра сведений.

Нужно получить результирующую таблицу:
Изм1, Изм2,...ИзмН   Рес1, ...РесМ Статус

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

При этом в Рес1, ... РесМ копируются значения из другой таблицы значений.

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

Вот код (отлаженный и проверенный):

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


От Гения 1С: Другой вариант решения задачи здесь Книга знаний: v8: Алгоритм синхронизации (сравнения) двух таблиц (по текстовому полю)

От Джамшута:
      ИначеЕсли Стр.___ТЗНачИндекс=0 Тогда //надо заменить на

      ИначеЕсли Стр.___ТЗКонИндекс=0 Тогда //должен быть контроль

Закладка

Описание | Рубрикатор | Поиск | ТелепатБот | Захваченные статьи | Установки | Форум
© Станислав Митичкин (Волшебник), 2005-2011 | Mista.ru

Яндекс.Метрика