В процессе разработки на платформе 1С:Предприятие 8 программисты часто сталкиваются с ситуацией, когда в параметрах запроса имеется строковое значение (например, название организации или артикул товара), а в базе данных соответствующее поле имеет тип Ссылка. Прямое сравнение Справочник.Ссылка = &Строка приведет к ошибке несовместимости типов или к пустому результату. В данной статье мы подробно разберем, как правильно реализовать такое сравнение, какие методы существуют и какой из них является наиболее оптимальным с точки зрения производительности.
Самый простой и очевидный способ — обратиться к строковому полю связанного справочника непосредственно в тексте запроса. Платформа 1С позволяет «проходить» через ссылочные поля к их реквизитам.
Рассмотрим пример, где нам нужно найти сотрудников конкретной организации, имея на руках только её название в переменной Заказчик:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Сотрудники.Ссылка КАК Ссылка,
| Сотрудники.Наименование КАК Наименование
|ИЗ
| Справочник.СотрудникиЗаказчика КАК Сотрудники
|ГДЕ
| Сотрудники.Организация.Наименование = &ОрганизацияНаименование";
Запрос.УстановитьПараметр("ОрганизацияНаименование", Заказчик);
Выборка = Запрос.Выполнить().Выбрать();
Преимущества: Простота написания и читаемость кода.
Недостатки: Низкая надежность. Если в справочнике Организации окажутся два элемента с одинаковым наименованием, запрос выберет сотрудников обеих организаций. Также стоит учитывать вопросы производительности, которые мы разберем ниже.
Если нам нужно найти данные по частичному совпадению строки или если мы хотим использовать системное представление объекта, можно прибегнуть к оператору ПОДОБНО. Проанализируем ситуацию, когда поиск ведется по маске:
|ГДЕ
| Сотрудники.Организация.Представление ПОДОБНО ""%"" + &Организация + ""%""
Здесь используется поле Представление. Важно понимать, что это поле является виртуальным. На уровне СУБД 1С преобразует его в выборку основной текстовой колонки справочника (обычно это Наименование или Код). Использование ПОДОБНО в сочетании с Представление крайне не рекомендуется на больших таблицах, так как это гарантированно приводит к полному сканированию таблицы (Full Table Scan) в SQL, игнорируя индексы.
Проанализируем наиболее правильный подход с точки зрения архитектуры 1С. Вместо того чтобы заставлять СУБД сопоставлять строки в сложном запросе, мы можем заранее найти ссылку на объект в коде 1С:Предприятия и передать её в запрос как готовый параметр.
Выясним, как это выглядит на практике:
// 1. Ищем ссылку по строке
СсылкаОрганизация = Справочники.Организации.НайтиПоНаименованию(Заказчик);
Если СсылкаОрганизация.Пустая() Тогда
Сообщить("Организация с таким названием не найдена!");
Возврат;
КонецЕсли;
// 2. Выполняем запрос, сравнивая ссылки (самый быстрый способ)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Сотрудники.Ссылка
|ИЗ
| Справочник.СотрудникиЗаказчика КАК Сотрудники
|ГДЕ
| Сотрудники.Организация = &Организация";
Запрос.УстановитьПараметр("Организация", СсылкаОрганизация);
Этот метод считается эталонным, так как сравнение по ссылке внутри СУБД происходит по внутреннему идентификатору (UUID), который всегда проиндексирован и работает максимально быстро.
Рассмотрим техническую сторону вопроса производительности, которую часто обсуждают на форумах. Когда вы пишете Сотрудники.Организация.Наименование, платформа автоматически генерирует LEFT OUTER JOIN (левое соединение) с таблицей справочника организаций.
Проанализируем риски:
Организация имеет составной тип (например, это может быть и Справочник.Организации, и Справочник.Контрагенты), то при обращении «через точку» 1С создаст соединения со всеми возможными таблицами этого типа. Это может привести к огромному SQL-запросу, который будет выполняться крайне медленно.ЛЕВОЕ СОЕДИНЕНИЕ в тексте запроса часто работает стабильнее, так как вы жестко задаете структуру связей.В некоторых обсуждениях встречается совет использовать ВЫРАЗИТЬ(Поле КАК СТРОКА). Важно помнить: в языке запросов 1С функция ВЫРАЗИТЬ не умеет превращать Ссылку в Строку. Она предназначена либо для ограничения длины строк неограниченной длины, либо для приведения составного типа к конкретному ссылочному типу. При необходимости соединять или фильтровать данные таким образом можно применить решение для сравнения строки с представлением ссылки в запросе.
Если вам все же необходимо выполнить соединение по строке внутри запроса, используйте явное соединение:
"ВЫБРАТЬ
| Сотрудники.Ссылка
|ИЗ
| Справочник.СотрудникиЗаказчика КАК Сотрудники
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Организации КАК ТаблицаОрганизаций
| ПО Сотрудники.Организация = ТаблицаОрганизаций.Ссылка
|ГДЕ
| ТаблицаОрганизаций.Наименование = &ОрганизацияНаименование"
Резюме: Если у вас есть возможность найти ссылку в коде до выполнения запроса — делайте это. Это избавит вас от проблем с уникальностью наименований и обеспечит максимальную скорость работы программы. Если же поиск по строке неизбежен внутри запроса, используйте прямое обращение к .Наименование, предварительно убедившись, что поле не является составным.