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