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

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

В современных типовых конфигурациях 1С, таких как Управление торговлей 11, ERP 2 или Комплексная автоматизация 2, контактная информация (КИ) контрагентов может храниться с поддержкой истории изменений. Это означает, что для одного и того же вида контактной информации (например, «Фактический адрес») в системе может существовать несколько записей с разными датами начала действия. Перед разработчиком часто встает задача: как получить именно актуальный адрес на конкретную дату, особенно если нужно сформировать отчет по списку контрагентов.

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

Постановка задачи и структура данных

Контактная информация в 1С:УТ 11 хранится в табличной части КонтактнаяИнформация справочника Контрагенты. Ключевым реквизитом для работы с историей является ДействуетС. Если этот реквизит заполнен, система считает, что запись актуальна, начиная с этой даты.

Рассмотрим ситуацию, когда нам необходимо получить последние адреса не для одного конкретного контрагента, а для целого списка (например, для выборки в отчет). Проблема заключается в том, что использование конструкции ПЕРВЫЕ 1 в данном случае невозможно, так как она ограничит весь результат запроса одной строкой, а нам нужна «последняя» строка для каждого контрагента в списке.

Решение задачи для списка контрагентов через временную таблицу

Наиболее оптимальный и правильный подход при работе со списками — использование временных таблиц для предварительного поиска максимальных дат. Разберем этот алгоритм по шагам.

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

Шаг 2. Соединение с основной таблицей. После того как мы нашли «контрольные точки» (пары Ссылка + Вид + МаксимальнаяДата), мы соединяем эту временную таблицу с исходной табличной частью, чтобы вытянуть само текстовое представление адреса или другие поля.

Проанализируем пример запроса, реализующего эту логику:


// Помещаем во временную таблицу ссылки и максимальные даты актуальности
ВЫБРАТЬ
    КонтрагентыКИ.Ссылка КАК Ссылка,
    МАКСИМУМ(КонтрагентыКИ.ДействуетС) КАК ДействуетС,
    КонтрагентыКИ.Вид КАК Вид
ПОМЕСТИТЬ ВремАктуальныеДаты
ИЗ
    Справочник.Контрагенты.КонтактнаяИнформация КАК КонтрагентыКИ
ГДЕ
    КонтрагентыКИ.Вид = &Вид
    И КонтрагентыКИ.ДействуетС <= &ДатаСреза
СГРУППИРОВАТЬ ПО
    КонтрагентыКИ.Ссылка,
    КонтрагентыКИ.Вид;

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

Важный нюанс: борьба с дублями

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

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

Проанализируем уточненную схему поиска через номер строки:

  1. Находим МАКСИМУМ(ДействуетС) для каждого контрагента и вида КИ.
  2. Во второй временной таблице находим МАКСИМУМ(НомерСтроки) для тех записей, у которых дата равна найденному максимуму.
  3. В финальном запросе соединяемся по Ссылка, Вид и НомерСтроки.

Использование функций БСП для получения контактной информации

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

Основным методом для этой задачи является функция КонтактнаяИнформацияОбъектов общего модуля УправлениеКонтактнойИнформацией. Рассмотрим пример её вызова:


// Подготовим список контрагентов
СписокСсылок = Новый Массив;
СписокСсылок.Добавить(СсылкаНаКонтрагента1);
СписокСсылок.Добавить(СсылкаНаКонтрагента2);

// Определим вид контактной информации (например, Юридический адрес)
ВидКИ = Справочники.ВидыКонтактнойИнформации.ЮрАдресКонтрагента;

// Получим таблицу с актуальными данными на текущую дату
ТаблицаАдресов = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияОбъектов(
    СписокСсылок, 
    ВидКИ, 
    ТекущаяДата(), 
    Истина // ТолькоАктуальные
);

// Теперь мы можем обойти результат
Для Каждого СтрокаАдреса Из ТаблицаАдресов Цикл
    Сообщить("Контрагент: " + СтрокаАдреса.Объект + " - Адрес: " + СтрокаАдреса.Представление);
КонецЦикла;

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

Особенности реквизита «ЗначенияПолей»

Выясним еще одну важную деталь. Реквизит Представление — это просто текстовая строка. Однако 1С хранит адрес в структурированном виде (индекс, город, улица) в реквизите ЗначенияПолей (обычно в формате JSON или XML). Если в вашем запросе или отчете нужно вывести город отдельно от улицы, вам не поможет простое получение Представление.

В таких случаях алгоритм следующий:

  1. Запросом получаем актуальную строку табличной части, как описано выше, но выбираем поле ЗначенияПолей.
  2. Используем функцию УправлениеКонтактнойИнформацией.КонтактнаяИнформацияВФорматеJSON (или аналогичные для XML), чтобы распарсить данные.
  3. Извлекаем нужную часть адреса.

Оптимизация производительности при больших объемах

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

Для оптимизации можно применить следующий подход: выбираем все записи контактной информации для нужных контрагентов в обычную таблицу значений, сортируем её по убыванию даты и номера строки, а затем используем метод Свернуть по колонке Ссылка (предварительно убедившись, что самая актуальная запись оказалась первой). В оперативной памяти 1С такие операции зачастую проходят быстрее, чем сложные JOIN на уровне SQL-сервера при работе с табличными частями справочников.

Резюме

Для получения актуального адреса из истории в 1С:

← На главную