Как в запросе 1С сравнить данные из регистра сведений и таблицы значений, чтобы найти новые и измененные записи?

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

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

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

Решение 1: Универсальный метод с помощью ПОЛНОГО СОЕДИНЕНИЯ

Это наиболее мощный и правильный способ для задачи полной синхронизации. ПОЛНОЕ СОЕДИНЕНИЕ (FULL OUTER JOIN) позволяет объединить данные из обеих таблиц, не теряя ни одной записи. Если для записи из одной таблицы не нашлось соответствия в другой, поля второй таблицы будут заполнены значением NULL.

Рассмотрим подробнее, как это работает. Такой подход позволяет нам за один запрос получить всю необходимую информацию для анализа:

  1. Новые записи, которые нужно добавить в регистр. Это строки, которые есть в нашей ТаблицеЗначений, но отсутствуют в РегистреСведений. В результате запроса у таких строк поля со стороны регистра будут иметь значение NULL.
  2. Удаленные записи, которые нужно удалить из регистра. Это строки, которые есть в РегистреСведений, но их уже нет в ТаблицеЗначений. У таких строк, наоборот, поля со стороны ТЗ будут NULL.
  3. Существующие записи, которые нужно проверить на изменения. Это строки, у которых нашлось соответствие по ключевым полям в обеих таблицах. Для них мы можем в запросе напрямую сравнить значения ресурсов.

Посмотрим на пример. Допустим, у нас есть ключевое поле Номенклатура и ресурс Цена.


ВЫБРАТЬ
    ВЫБОР
        КОГДА Источник.Номенклатура ЕСТЬ NULL
            ТОГДА Регистр.Номенклатура
        ИНАЧЕ Источник.Номенклатура
    КОНЕЦ КАК Номенклатура,
    Источник.Цена КАК НоваяЦена,
    Регистр.Цена КАК СтараяЦена,
    ВЫБОР
        КОГДА Регистр.Номенклатура ЕСТЬ NULL
            ТОГДА "Новая"
        КОГДА Источник.Номенклатура ЕСТЬ NULL
            ТОГДА "Удалить"
        КОГДА Источник.Цена <> Регистр.Цена
            ТОГДА "Изменена"
        ИНАЧЕ "Не изменилась"
    КОНЕЦ КАК СтатусЗаписи
ИЗ
    ТаблицаЗначений КАК Источник
        ПОЛНОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК Регистр
        ПО Источник.Номенклатура = Регистр.Номенклатура

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

Решение 2: Использование ЛЕВОГО СОЕДИНЕНИЯ

ЛЕВОЕ СОЕДИНЕНИЕ (LEFT JOIN) также можно использовать, но этот подход имеет свои нюансы и ограничения. Ключевой момент — какая таблица является основной (левой). От этого зависит, какую часть задачи мы решим.

Вариант А: Основная таблица — Таблица Значений (данные из файла)

Разберем по шагам. Мы берем все записи из нашей ТЗ и "присоединяем" к ним данные из регистра по совпадающему ключу. Если в регистре соответствия нет, поля из него будут NULL.


ВЫБРАТЬ
    Источник.Номенклатура,
    Источник.Цена,
    Регистр.Цена КАК ЦенаВРегистре
ИЗ
    ТаблицаЗначений КАК Источник
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК Регистр
        ПО Источник.Номенклатура = Регистр.Номенклатура

Проанализируем результат этого запроса:

Важный недостаток этого подхода: мы не сможем выявить записи, которые нужно удалить. Запрос вернет только те данные, которые есть в исходном файле (ТЗ), и полностью проигнорирует записи регистра, которых в этом файле нет.

Вариант Б: Как найти записи для удаления с помощью ЛЕВОГО СОЕДИНЕНИЯ?

Чтобы найти записи, которые есть в регистре, но отсутствуют в файле, нам потребуется выполнить второй, "обратный" запрос. В нем основной (левой) таблицей будет уже РегистрСведений.


ВЫБРАТЬ
    Регистр.Номенклатура
ИЗ
    РегистрСведений.ЦеныНоменклатуры КАК Регистр
        ЛЕВОЕ СОЕДИНЕНИЕ ТаблицаЗначений КАК Источник
        ПО Регистр.Номенклатура = Источник.Номенклатура
ГДЕ
    Источник.Номенклатура ЕСТЬ NULL

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

Итоги

Давайте подведем итог и выберем оптимальный путь.

Таким образом, выбор метода зависит от конечной цели. Для полной и надежной синхронизации ваш выбор — ПОЛНОЕ СОЕДИНЕНИЕ.

← К списку