Как в 1С найти связанные документы по тексту в комментарии?

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

В процессе работы с 1С часто возникает нестандартная задача: найти связь между двумя документами, когда эта связь не оформлена через специальный реквизит типа ДокументСсылка, а хранится в виде простого текста в поле «Комментарий». Например, в документе «Корректировка регистров» может быть комментарий вида: «Создано для Реализация товаров и услуг №000988 от 21.01.2021». Перед нами стоит задача сопоставить эти документы программно.

Основная сложность заключается в том, что язык запросов 1С не позволяет в условии соединения ПО напрямую сравнивать поле одной таблицы с результатом функции ПРЕДСТАВЛЕНИЕ() для поля другой таблицы. Оператор ПОДОБНО также ожидает статическую строку или параметр, а не поле из другой таблицы. Давайте разберем несколько способов решения этой задачи, от самого простого до наиболее производительного и архитектурно правильного.

Решение 1: Запрос в цикле (Простой, но неоптимальный подход)

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

Рассмотрим алгоритм по шагам:

  1. Получаем список (массив, таблицу значений) ссылок на исходные документы, представления которых мы будем искать.
  2. Организуем цикл по этому списку.
  3. На каждой итерации цикла получаем строковое представление текущего документа (например, через функцию Строка()).
  4. Формируем текст для поиска с помощью оператора ПОДОБНО, добавляя символы `%` по краям.
  5. Передаем эту строку как параметр в запрос, который ищет ее в поле «Комментарий» второго типа документов.
  6. Если документ найден, сопоставляем его с исходным документом из цикла.

Посмотрим на пример кода, который реализует этот подход:

В данном примере функция принимает на вход ссылку на документ-основание (назовем его «Операция») и ищет связанную с ним «Корректировку регистров».


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

Плюсы и минусы данного метода:

(+) Простота: Код легко читается и реализуется, не требует глубоких знаний языка запросов.

(-) Производительность: Это самый большой недостаток. Если у вас 1000 исходных документов, будет выполнено 1000 отдельных запросов к серверу СУБД. На больших объемах данных такая обработка будет работать крайне медленно и создавать избыточную нагрузку на сервер. Этот подход допустим только для разовых операций на небольшом количестве документов (десятки, но не тысячи).

Решение 2: Пакетный запрос с временными таблицами (Оптимальный подход)

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

Шаг 1: Извлечение данных из комментария и помещение во временную таблицу.

Сначала мы создадим запрос, который выберет все документы, в комментарии которых есть нужная нам информация. С помощью строковых функций ПОДСТРОКА() и НАЙТИ() мы "расшифруем" комментарий и извлечем из него ключевые данные для связи — номер и дату документа. Результат мы поместим во временную таблицу (ВТ).

Шаг 2: Соединение временной таблицы с искомыми документами.

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

Посмотрим на пример такого пакетного запроса:


ВЫБРАТЬ
    ДокКорректировки.Ссылка КАК СсылкаНаКорректировку,
    ПОДСТРОКА(ДокКорректировки.Комментарий, НАЙТИ(ДокКорректировки.Комментарий, "№") + 1, 11) КАК НомерДокумента,
    ПОДСТРОКА(ДокКорректировки.Комментарий, НАЙТИ(ДокКорректировки.Комментарий, " от ") + 4, 10) КАК ДатаДокументаСтрокой
ПОМЕСТИТЬ ВТ_РазобранныеКомментарии
ИЗ
    Документ.КорректировкаРегистров КАК ДокКорректировки
ГДЕ
    // Предварительный отбор, чтобы уменьшить выборку
    ДокКорректировки.Комментарий ПОДОБНО "Создано для Реализация товаров и услуг №%";

ВЫБРАТЬ
    ВТ.СсылкаНаКорректировку,
    Реализации.Ссылка КАК СсылкаНаРеализацию
ИЗ
    ВТ_РазобранныеКомментарии КАК ВТ
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК Реализации
        ПО ВТ.НомерДокумента = Реализации.Номер
        // Соединение по дате сложнее, т.к. дата у нас в виде строки.
        // Нужно привести дату из документа к строке или наоборот.
        // Более надежный вариант - преобразовать строку в дату на стороне 1С или СУБД,
        // но для примера можно сравнить строковые представления.
        И ПОДСТРОКА(ВТ.ДатаДокументаСтрокой, 7, 4) + ПОДСТРОКА(ВТ.ДатаДокументаСтрокой, 4, 2) + ПОДСТРОКА(ВТ.ДатаДокументаСтрокой, 1, 2) = ФОРМАТ(Реализации.Дата, "ДФ=ггггММдд")
;

Важные моменты:

Решение 3: Архитектурно правильный подход (для будущих разработок)

Хранение структурированной информации, такой как ссылка на другой объект, в текстовом поле — это плохая практика. Комментарий предназначен для неструктурированной информации для пользователя, а не для машинной обработки. Хотя для разовой акции предыдущие методы подойдут, для регулярных операций систему стоит доработать.

Правильное решение — использовать регистр сведений.

  1. Создайте новый регистр сведений. Назовите его, например, «СвязанныеДокументы». Он может быть непериодическим.
  2. Определите измерения. В регистре будет два измерения (или измерение и ресурс) с типом ДокументСсылка. Например:
    • ДокументОснование (тип ДокументСсылка.РеализацияТоваровУслуг)
    • СвязанныйДокумент (тип ДокументСсылка.КорректировкаРегистров)
  3. Доработайте алгоритм создания документов. В том месте кода, где создается документ «КорректировкаРегистров», добавьте запись в новый регистр, явно указывая связь между двумя документами.

Преимущества такого подхода:

Хотя этот метод требует изменения конфигурации, он является наиболее профессиональным и избавляет от подобных проблем в будущем.

← На главную