В процессе работы с 1С часто возникает нестандартная задача: найти связь между двумя документами, когда эта связь не оформлена через специальный реквизит типа ДокументСсылка, а хранится в виде простого текста в поле «Комментарий». Например, в документе «Корректировка регистров» может быть комментарий вида: «Создано для Реализация товаров и услуг №000988 от 21.01.2021». Перед нами стоит задача сопоставить эти документы программно.
Основная сложность заключается в том, что язык запросов 1С не позволяет в условии соединения ПО напрямую сравнивать поле одной таблицы с результатом функции ПРЕДСТАВЛЕНИЕ() для поля другой таблицы. Оператор ПОДОБНО также ожидает статическую строку или параметр, а не поле из другой таблицы. Давайте разберем несколько способов решения этой задачи, от самого простого до наиболее производительного и архитектурно правильного.
Это первое решение, которое часто приходит на ум, и именно его реализовал автор вопроса на форуме. Суть метода заключается в том, чтобы перебрать исходные документы в цикле и для каждого из них выполнять отдельный запрос к базе данных.
Рассмотрим алгоритм по шагам:
Строка()).ПОДОБНО, добавляя символы `%` по краям.Посмотрим на пример кода, который реализует этот подход:
В данном примере функция принимает на вход ссылку на документ-основание (назовем его «Операция») и ищет связанную с ним «Корректировку регистров».
Функция ПолучитьКорректировку(Операция)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| КорректировкаРегистров.Ссылка КАК Ссылка
|ИЗ
| Документ.КорректировкаРегистров КАК КорректировкаРегистров
|ГДЕ
| КорректировкаРегистров.Комментарий ПОДОБНО &Комментарий";
// Формируем параметр для поиска. Строка(Операция) даст нам представление документа
Запрос.УстановитьПараметр("Комментарий", "%" + Строка(Операция) + "%");
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Результат = Выборка.Ссылка;
Иначе
Результат = Документы.КорректировкаРегистров.ПустаяСсылка();
КонецЕсли;
Возврат Результат;
КонецФункции
Плюсы и минусы данного метода:
(+) Простота: Код легко читается и реализуется, не требует глубоких знаний языка запросов.
(-) Производительность: Это самый большой недостаток. Если у вас 1000 исходных документов, будет выполнено 1000 отдельных запросов к серверу СУБД. На больших объемах данных такая обработка будет работать крайне медленно и создавать избыточную нагрузку на сервер. Этот подход допустим только для разовых операций на небольшом количестве документов (десятки, но не тысячи).
Чтобы избежать многократных обращений к базе данных, можно решить всю задачу в рамках одного пакетного запроса. Этот метод является наиболее производительным и рекомендуемым для обработки данных в 1С. Мы разобьем задачу на два логических шага, используя временные таблицы.
Шаг 1: Извлечение данных из комментария и помещение во временную таблицу.
Сначала мы создадим запрос, который выберет все документы, в комментарии которых есть нужная нам информация. С помощью строковых функций ПОДСТРОКА() и НАЙТИ() мы "расшифруем" комментарий и извлечем из него ключевые данные для связи — номер и дату документа. Результат мы поместим во временную таблицу (ВТ).
Шаг 2: Соединение временной таблицы с искомыми документами.
Вторым запросом в пакете мы соединим нашу временную таблицу (уже содержащую структурированные номер и дату) с таблицей искомых документов. Так как теперь у нас есть отдельные поля для номера и даты, мы можем выполнить эффективное соединение по точному равенству.
Посмотрим на пример такого пакетного запроса:
ВЫБРАТЬ
ДокКорректировки.Ссылка КАК СсылкаНаКорректировку,
ПОДСТРОКА(ДокКорректировки.Комментарий, НАЙТИ(ДокКорректировки.Комментарий, "№") + 1, 11) КАК НомерДокумента,
ПОДСТРОКА(ДокКорректировки.Комментарий, НАЙТИ(ДокКорректировки.Комментарий, " от ") + 4, 10) КАК ДатаДокументаСтрокой
ПОМЕСТИТЬ ВТ_РазобранныеКомментарии
ИЗ
Документ.КорректировкаРегистров КАК ДокКорректировки
ГДЕ
// Предварительный отбор, чтобы уменьшить выборку
ДокКорректировки.Комментарий ПОДОБНО "Создано для Реализация товаров и услуг №%";
ВЫБРАТЬ
ВТ.СсылкаНаКорректировку,
Реализации.Ссылка КАК СсылкаНаРеализацию
ИЗ
ВТ_РазобранныеКомментарии КАК ВТ
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК Реализации
ПО ВТ.НомерДокумента = Реализации.Номер
// Соединение по дате сложнее, т.к. дата у нас в виде строки.
// Нужно привести дату из документа к строке или наоборот.
// Более надежный вариант - преобразовать строку в дату на стороне 1С или СУБД,
// но для примера можно сравнить строковые представления.
И ПОДСТРОКА(ВТ.ДатаДокументаСтрокой, 7, 4) + ПОДСТРОКА(ВТ.ДатаДокументаСтрокой, 4, 2) + ПОДСТРОКА(ВТ.ДатаДокументаСтрокой, 1, 2) = ФОРМАТ(Реализации.Дата, "ДФ=ггггММдд")
;
Важные моменты:
Хранение структурированной информации, такой как ссылка на другой объект, в текстовом поле — это плохая практика. Комментарий предназначен для неструктурированной информации для пользователя, а не для машинной обработки. Хотя для разовой акции предыдущие методы подойдут, для регулярных операций систему стоит доработать.
Правильное решение — использовать регистр сведений.
ДокументСсылка. Например:
ДокументОснование (тип ДокументСсылка.РеализацияТоваровУслуг)СвязанныйДокумент (тип ДокументСсылка.КорректировкаРегистров)Преимущества такого подхода:
Хотя этот метод требует изменения конфигурации, он является наиболее профессиональным и избавляет от подобных проблем в будущем.