Как сравнить две таблицы значений и выровнять остатки между базами 1С

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

В процессе сопровождения систем 1С часто возникает задача синхронизации данных между различными конфигурациями, например, между 1С:Управление торговлей (УТ) и 1С:Бухгалтерия предприятия (БП). Одной из типичных задач является выравнивание остатков: когда в одной базе (УТ) оперативный учет верный, а в другой (БП) данные разошлись. Для решения этой задачи нам необходимо получить две таблицы значений (ТЗ) с остатками из обеих баз, сравнить их и на основании разницы сформировать документы «Оприходование товаров» или «Списание товаров».

В этой статье мы подробно разберем, как технически реализовать сравнение двух ТаблицаЗначений быстро и эффективно, используя механизмы платформы 1С.

Метод 1: Использование запроса и временных таблиц (Рекомендуемый)

Проанализируем наиболее производительный способ. Вместо того чтобы перебирать таблицы в циклах, мы можем передать их в запрос и выполнить соединение на уровне СУБД (или внутреннего движка запросов 1С). Это позволит нам использовать всю мощь языка запросов, включая агрегатные функции и условия.

Разберем процесс по шагам:

  1. Подготовка таблиц значений. Для того чтобы передать ТЗ в запрос, колонки таблиц должны быть жестко типизированы. Если колонки будут иметь составной тип или тип «Произвольный», запрос может отработать некорректно.
  2. Загрузка в менеджер временных таблиц. Мы помещаем обе таблицы во временные таблицы (ВТ).
  3. Выполнение ПОЛНОГО СОЕДИНЕНИЯ. Это критически важно, так как товары могут присутствовать в УТ, но отсутствовать в БП, и наоборот.

Рассмотрим пример кода для реализации этого метода:


// Предположим, у нас уже есть ТЗ_УТ и ТЗ_БП с колонками "НоменклатураСтр" и "Количество"
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;

// Передаем таблицы в параметры запроса
Запрос.УстановитьПараметр("ТЗ_УТ", ТЗ_УТ);
Запрос.УстановитьПараметр("ТЗ_БП", ТЗ_БП);

// Помещаем первую таблицу во временную
Запрос.Текст = 
"ВЫБРАТЬ
|	ТЗ.НоменклатураСтр КАК НоменклатураСтр,
|	ТЗ.Количество КАК Количество
|ПОМЕСТИТЬ ВТ_УТ
|ИЗ
|	&ТЗ_УТ КАК ТЗ;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|	ТЗ.НоменклатураСтр КАК НоменклатураСтр,
|	ТЗ.Количество КАК Количество
|ПОМЕСТИТЬ ВТ_БП
|ИЗ
|	&ТЗ_БП КАК ТЗ";

Запрос.Выполнить();

// Основной запрос сравнения
Запрос.Текст = 
"ВЫБРАТЬ
|	ЕСТЬNULL(ВТ_УТ.НоменклатураСтр, ВТ_БП.НоменклатураСтр) КАК НоменклатураСтр,
|	ЕСТЬNULL(ВТ_УТ.Количество, 0) КАК КолУТ,
|	ЕСТЬNULL(ВТ_БП.Количество, 0) КАК КолБП,
|	ЕСТЬNULL(ВТ_УТ.Количество, 0) - ЕСТЬNULL(ВТ_БП.Количество, 0) КАК Разница
|ИЗ
|	ВТ_УТ КАК ВТ_УТ
|		ПОЛНОЕ СОЕДИНЕНИЕ ВТ_БП КАК ВТ_БП
|		ПО ВТ_УТ.НоменклатураСтр = ВТ_БП.НоменклатураСтр
|ГДЕ
|	ЕСТЬNULL(ВТ_УТ.Количество, 0) - ЕСТЬNULL(ВТ_БП.Количество, 0) <> 0";

РезультатСравнения = Запрос.Выполнить().Выгрузить();

В данном примере мы используем ПОЛНОЕ СОЕДИНЕНИЕ, что позволяет нам увидеть позиции, которые есть только в одной из баз. С помощью функции ЕСТЬNULL мы заменяем отсутствующие значения нулями, что позволяет вычислить разницу.

Метод 2: Сравнение в памяти с использованием индексов

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

Выясним, как ускорить этот процесс. Рассмотрим применение метода Индексы.Добавить(). Создание индекса по ключевому полю (например, «Артикул») превращает поиск из перебора всей таблицы в быстрый поиск по хеш-таблице.

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


// Индексируем таблицу БП для быстрого поиска
ТЗ_БП.Индексы.Добавить("Артикул");

Для Каждого СтрокаУТ Из ТЗ_УТ Цикл
    // Ищем соответствующую строку в БП
    СтрокаБП = ТЗ_БП.Найти(СтрокаУТ.Артикул, "Артикул");
    
    Если СтрокаБП <> Неопределено Тогда
        Разница = СтрокаУТ.Количество - СтрокаБП.Количество;
        // Обрабатываем разницу
        СтрокаБП.Обработана = Истина; // Помечаем, что строку нашли
    Иначе
        // Товара нет в БП - это чистое оприходование
        Разница = СтрокаУТ.Количество;
    КонецЕсли;
КонецЦикла;

// В конце нужно пройтись по ТЗ_БП и найти те строки, которые НЕ были помечены как "Обработана"
// Это товары, которые есть в БП, но их нет в УТ - их нужно списать.

Метод 3: Использование объекта «Соответствие»

Объект Соответствие (или Кэш) работает крайне быстро. Мы можем загрузить одну из таблиц в Соответствие, где ключом будет уникальный идентификатор или артикул, а значением — количество.

Разберем по шагам этот подход:

  1. Создаем объект Новый Соответствие.
  2. Заполняем его данными из первой базы (БП).
  3. Обходим вторую базу (УТ) и сравниваем значения.

Этот метод удобен тем, что Соответствие потребляет меньше памяти, чем полноценная ТаблицаЗначений, и доступ к элементу по ключу происходит мгновенно.

Важные нюансы идентификации

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

Обработка характеристик и единиц измерения

Часто в 1С:УТ учет ведется по характеристикам, а в 1С:БП — просто по номенклатуре. Перед сравнением таблицу из УТ необходимо «свернуть». Используйте метод ТЗ_УТ.Свернуть("Номенклатура", "Количество"). Это позволит объединить остатки всех характеристик в одну строку, сопоставимую с данными бухгалтерии.

Также проанализируем единицы измерения. Если УТ хранит данные в упаковках, а БП в штуках, при сравнении необходимо умножать количество на коэффициент упаковки, иначе вы получите ложные расхождения.

Итог: как быстро сделать оприходование/списание

После того как вы получили таблицу РезультатСравнения с колонкой Разница, алгоритм прост:

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

← На главную