Почему запрос в 1С возвращает пустой результат при поиске по введенному тексту

Программист 1С v8.3 (Обычные формы) 1C:Бухгалтерия Бухгалтерский учет IT и автоматизация бизнеса
← На главную

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

Причина 1: Несоответствие типов данных (сравнение ссылки со строкой)

Проанализируем типичную ошибку в секции условий запроса:


ГДЕ
    МестонахождениеОССрезПоследних.ИнвНомер.Ссылка = &ИнвНомер

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

Для корректной работы необходимо либо выполнять поиск по строковым реквизитам (коду или наименованию), либо предварительно получить саму ссылку перед выполнением запроса:


// Предварительный поиск ссылки по коду
СсылкаНаОС = Справочники.ОсновныеСредства.НайтиПоКоду(Текст);
Если ЗначениеЗаполнено(СсылкаНаОС) Тогда
    Запрос.УстановитьПараметр("ОсновноеСредство", СсылкаНаОС);
КонецЕсли;

Причина 2: Формат кода и несовпадение лидирующих нулей

Если код справочника в метаданных имеет строковый тип фиксированной длины с автонумерацией (например, длина 9 символов: 000000123), а пользователь вводит с клавиатуры число без нулей (123), проверка на строгое равенство ОсновныеСредства.Код = &Код вернет пустой результат.

Для устранения этой проблемы строковый код перед передачей в запрос необходимо нормализовать с помощью дополнения лидирующими нулями:


// Дополнение кода нулями до заданной длины (например, 9 знаков)
НужныйКод = Формат(Число(Текст), "ЧЦ=9; ЧВН=; ЧГ=0");
Запрос.УстановитьПараметр("Код", НужныйКод);

Если используется Библиотека Стандартных Подсистем (БСП), можно применить готовую функцию:


НужныйКод = ОбщегоНазначенияКлиентСервер.ДополнитьСтроку(СокрЛП(Текст), 9, "0", "Слева");

Причина 3: Ошибки в структуре запроса и соединениях таблиц

Перечисление нескольких таблиц через запятую в секции ИЗ приводит к неявному полному декартову произведению. Если хотя бы в одной из таблиц нет записи, удовлетворяющей условиям секции ГДЕ, весь результат запроса окажется пустым. Кроме того, наложение условий на виртуальные таблицы (например, СрезПоследних) в секции ГДЕ крайне неэффективно.

Рассмотрим правильный подход: отборы для виртуальных таблиц следует передавать в параметры самой таблицы, а связи между сущностями строить через явные соединения ЛЕВОЕ СОЕДИНЕНИЕ.


ВЫБРАТЬ
    ОсновныеСредства.Наименование КАК Наименование,
    ОсновныеСредства.ПервоначальнаяСтоимость КАК ПервоначальнаяСтоимость,
    ОсновныеСредства.КодПоОКОФ КАК КодПоОКОФ,
    ОсновныеСредства.АмортизационнаяГруппа КАК АмортизационнаяГруппа,
    ОсновныеСредства.ЗаводскойНомер КАК ЗаводскойНомер,
    ОсновныеСредства.Код КАК Код,
    МестонахождениеОССрезПоследних.Состояние КАК Состояние,
    СобытияПринято.ДатаСобытия КАК ПринятоКУчету,
    ЕСТЬNULL(СобытияСнято.ДатаСобытия, ДАТАВРЕМЯ(1, 1, 1)) КАК СнятоСУчета
ИЗ
    Справочник.ОсновныеСредства КАК ОсновныеСредства
    
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МестонахождениеОС.СрезПоследних(&Период, ОсновноеСредство = &СсылкаНаОС) КАК МестонахождениеОССрезПоследних
    ПО МестонахождениеОССрезПоследних.ОсновноеСредство = ОсновныеСредства.Ссылка
    
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СобытияОС КАК СобытияПринято
    ПО (СобытияПринято.ОсновноеСредство = ОсновныеСредства.Ссылка)
        И (СобытияПринято.Событие = &СобытиеПринятиеКУчету)
        
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СобытияОС КАК СобытияСнято
    ПО (СобытияСнято.ОсновноеСредство = ОсновныеСредства.Ссылка)
        И (СобытияСнято.Событие = &СобытиеСписание)
ГДЕ
    ОсновныеСредства.Ссылка = &СсылкаНаОС

Причина 4: Особенности события ОкончаниеВводаТекста

В процедуре-обработчике ОкончаниеВводаТекста важно не только извлечь данные, но и правильно завершить стандартную обработку события платформой:

  1. Передать найденную ссылку или значение в параметр Значение.
  2. Установить параметр СтандартнаяОбработка = Ложь, чтобы предотвратить стандартный поиск платформы, который может перезаписать или очистить результат.

Посмотрим на итоговый правильный алгоритм обработки события:


Процедура ТаблицаТоваровИнвНомерОкончаниеВводаТекста(Элемент, Текст, Значение, СтандартнаяОбработка)
    
    Если Не ЗначениеЗаполнено(Текст) Тогда
        Возврат;
    КонецЕсли;
    
    // 1. Нормализуем код и ищем объект метаданных
    КодОС = СокрЛП(Текст);
    НайденноеОС = Справочники.ОсновныеСредства.НайтиПоКоду(КодОС);
    
    Если Не ЗначениеЗаполнено(НайденноеОС) Тогда
        // Пробуем дополнить нулями при строковом коде
        КодСНулями = Формат(Число(КодОС), "ЧЦ=9; ЧВН=; ЧГ=0");
        НайденноеОС = Справочники.ОсновныеСредства.НайтиПоКоду(КодСНулями);
    КонецЕсли;
    
    Если ЗначениеЗаполнено(НайденноеОС) Тогда
        
        // 2. Отключаем стандартный поиск и подставляем найденный объект
        СтандартнаяОбработка = Ложь;
        Значение = НайденноеОС;
        
        // 3. Выполняем запрос по найденной ссылке для заполнения реквизитов
        Запрос = Новый Запрос;
        Запрос.Текст = 
            "ВЫБРАТЬ
            |   ОсновныеСредства.Наименование КАК Наименование,
            |   ОсновныеСредства.ПервоначальнаяСтоимость КАК ПервоначальнаяСтоимость,
            |   ОсновныеСредства.КодПоОКОФ КАК КодПоОКОФ,
            |   ОсновныеСредства.АмортизационнаяГруппа КАК АмортизационнаяГруппа
            |ИЗ
            |   Справочник.ОсновныеСредства КАК ОсновныеСредства
            |ГДЕ
            |   ОсновныеСредства.Ссылка = &СсылкаНаОС";
            
        Запрос.УстановитьПараметр("СсылкаНаОС", НайденноеОС);
        
        Выборка = Запрос.Выполнить().Выбрать();
        Если Выборка.Следующий() Тогда
            // Заполнение связанных реквизитов формы или строки
            НаименованиеОбъекта = Выборка.Наименование;
            ПервоначальнаяСтоимостьПолеВвода = Выборка.ПервоначальнаяСтоимость;
            ОКОФПолеВвода = Выборка.КодПоОКОФ;
            АмортизационнаяГруппаПолеВвода = Выборка.АмортизационнаяГруппа;
        КонецЕсли;
        
    КонецЕсли;

КонецПроцедуры
← На главную