Каждый разработчик 1С рано или поздно сталкивается с ситуацией, которая кажется мистической: запрос без условий выбирает данные корректно, но стоит добавить простейший фильтр через предложение ГДЕ, как результат становится пустым. При этом визуально данные в базе есть, и параметр в запрос передается. В этой статье мы подробно разберем, почему так происходит, и научимся диагностировать подобные ошибки типизации и логики.
Рассмотрим ситуацию на примере реального кода. Программист пытается сформировать отчет по лицевым счетам сотрудников с фильтром по конкретному банку. Код выглядит следующим образом:
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| ЛицевыеСчета.Владелец КАК Сотрудник,
| ЛицевыеСчета.Наименование КАК Наименование,
| ЛицевыеСчета.Банк.Наименование КАК Банк
|ИЗ
| Справочник.ЛицевыеСчета КАК ЛицевыеСчета
|ГДЕ
| ЛицевыеСчета.Банк = &БанкНаименование";
Запрос.УстановитьПараметр("БанкНаименование", Отчет.БанкН);
На первый взгляд, все верно. Однако запрос возвращает пустую выборку. Выясним причину, проанализировав наиболее вероятные сценарии возникновения такой ошибки.
В типовых конфигурациях 1С (таких как БП 3.0, ЗУП 3.1 или ERP) часто сосуществуют два очень похожих справочника: Банки и КлассификаторБанков. Проанализируем, как это влияет на запрос:
Если в реквизите ЛицевыеСчета.Банк хранится ссылка на Справочник.Банки, а в реквизите формы Отчет.БанкН пользователь выбрал значение из Справочник.КлассификаторБанков, то для системы 1С это абсолютно разные типы данных. Сравнение ЛицевыеСчета.Банк = &БанкНаименование всегда будет давать Ложь, даже если визуально названия банков полностью совпадают.
Решение: Убедитесь, что тип реквизита на форме отчета строго соответствует типу реквизита в базе данных. В нашем примере автору помогла замена типа реквизита БанкН на тип, соответствующий справочнику в объекте ЛицевыеСчета.
Посмотрим на ошибку, часто возникающую при невнимательном написании текста запроса. Рассмотрим пример некорректного условия:
|ГДЕ
| ЛицевыеСчета.Банк.Наименование = &БанкНаименование
И соответствующую установку параметра:
Запрос.УстановитьПараметр("БанкНаименование", Отчет.БанкН); // Здесь передается Ссылка
В данном случае мы пытаемся сравнить строковое наименование банка из базы данных со ссылкой на объект из параметров. Система не сможет привести их к одному типу автоматически, и условие не сработает. Чтобы исправить это, нужно либо сравнивать ссылки, либо передавать в параметр именно строку через Отчет.BankН.Наименование, однако сравнение по строке — это плохая практика.
Иногда визуально данные кажутся идентичными, но запрос их "не видит". Проанализируем внутреннее устройство ссылок. Каждый объект в 1С имеет уникальный идентификатор (GUID). Если в справочнике Банки по какой-то причине создано два элемента с одинаковым названием "Сбербанк", они будут иметь разные GUID.
Если лицевой счет привязан к "Сбербанку №1", а в фильтре отчета выбран "Сбербанк №2", запрос вернет пустое значение. В таких случаях рекомендуется использовать обработку "Поиск и замена дублей", чтобы объединить записи.
Выясним еще одну важную деталь. Справочники в 1С часто имеют иерархическую структуру. Если пользователь выбирает в качестве параметра Группу (папку) банков, а в лицевых счетах указаны конкретные Элементы, простое сравнение через оператор = не сработает.
Рассмотрим правильный подход: если вы хотите, чтобы при выборе папки в отчет попадали все банки внутри нее, используйте оператор В ИЕРАРХИИ.
Запрос.Текст = "ВЫБРАТЬ ... ИЗ ... ГДЕ ЛицевыеСчета.Банк В ИЕРАРХИИ(&Банк)";
Если вы все же вынуждены использовать поиск по наименованию (что крайне не рекомендуется), помните о "невидимых" препятствиях:
ПОДОБНО или прямое равенство могут учитывать разницу между "банк" и "БАНК".Проанализируем фрагмент кода автора: ОбъектНаСервере = РеквизитФормыВЗначение("Отчет");. Это стандартный метод для управляемых форм, но важно помнить о контексте. Если реквизит Отчет.БанкН был заполнен на клиенте, но данные еще не были переданы на сервер или форма не была синхронизирована, в запрос может попасть пустое значение.
Всегда проверяйте заполненность параметров перед выполнением запроса:
Если НЕ ЗначениеЗаполнено(Отчет.БанкН) Тогда
Сообщить("Не выбран банк для фильтрации!");
Возврат;
КонецЕсли;
Чтобы избежать подобных "фантастических" ситуаций, придерживайтесь следующих правил:
Подводя итог, можно сказать, что "чудес" в запросах 1С не бывает. Пустой результат при наличии данных — это всегда следствие несовпадения типов, использования разных справочников или некорректной обработки иерархии объектов. Тщательная проверка типов через ТипЗнч() и использование консоли запросов помогут вам быстро найти и устранить причину проблемы.