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

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При изучении механизмов работы с запросами в 1С:Предприятие 8 начинающие разработчики часто сталкиваются с ситуацией, когда код кажется верным, массив параметров заполнен данными, но результат выполнения запроса остается пустым. В данной статье мы подробно разберем, почему так происходит, проанализируем ошибки сопоставления типов данных и выясним, как правильно работать с условиями в запросах и секцией ИТОГИ.

Разбор первой причины: Несоответствие типов данных

Рассмотрим типичную ситуацию, представленную в вопросе. Программист пытается найти товары по их артикулам, используя условие В(&СписокАртикулов). Давайте проанализируем исходный код:


Запрос.Текст = "ВЫБРАТЬ
               | Номенклатура.Код,
               | Номенклатура.Наименование
               |ИЗ
               | Справочник.Номенклатура КАК Номенклатура
               |ГДЕ
               | Номенклатура.Артикул В(&СписокАртикулов)";

МассивСтр = Новый Массив;
МассивСтр.Добавить(Справочники.Номенклатура.НайтиПоРеквизиту("Артикул","K9543NT"));
Запрос.УстановитьПараметр("СписокАртикулов", МассивСтр);

Проблема заключается в том, что поле Номенклатура.Артикул в базе данных имеет тип Строка. Однако метод НайтиПоРеквизиту() возвращает объект типа СправочникСсылка.Номенклатура. В языке запросов 1С (как и в большинстве СУБД) невозможно напрямую сравнить уникальный идентификатор (ссылку) со строкой текста. Даже если в этой ссылке "внутри" записан нужный артикул, для системы это разные типы данных. В итоге условие ГДЕ всегда возвращает ЛОЖЬ, и результат запроса оказывается пустым.

Как исправить: Существует два способа решения в зависимости от того, что именно вы хотите найти.

  1. Поиск по артикулу (строке): Если у вас есть строковые значения артикулов, просто добавьте их в массив напрямую, без использования НайтиПоРеквизиту(). Это также значительно повысит производительность, так как исключит лишние обращения к базе данных перед самим запросом.
  2. Поиск по ссылке: Если вам нужно искать именно по ссылкам на элементы, измените текст запроса, чтобы условие проверяло поле Ссылка.

Проанализируем правильный вариант кода для поиска по строковым артикулам:


МассивАртикулов = Новый Массив;
МассивАртикулов.Добавить("K9543NT");
МассивАртикулов.Добавить("P0130TN");

Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ Артикул ИЗ Справочник.Номенклатура ГДЕ Артикул В(&СписокАртикулов)";
Запрос.УстановитьПараметр("СписокАртикулов", МассивАртикулов);

Эффективность и избыточность кода

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


// Плохой пример: избыточное действие
Ссылка = Справочники.Номенклатура.НайтиПоРеквизиту("Артикул", "K9543NT");
МассивСтр.Добавить(Ссылка.Артикул);

Такой подход крайне неэффективен. Метод НайтиПоРеквизиту — это отдельный скрытый запрос к базе данных. Если вы уже знаете строку артикула, нет никакого смысла "спрашивать" у базы ссылку на товар только для того, чтобы снова получить ту же самую строку артикула. Всегда стремитесь минимизировать количество обращений к серверу БД.

Ошибки при использовании секции ИТОГИ и символа ";"

Второй важный аспект проблемы касается синтаксиса запроса при использовании агрегатных функций и итогов. Разберем пример запроса, который выдавал ошибку или некорректный результат:


ВЫБРАТЬ
    Номенклатура.Код,
    Номенклатура.Наименование КАК Наименование
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    Номенклатура.ЭтоГруппа = ЛОЖЬ И Номенклатура.Ссылка В(&СписокАртикулов);
ИТОГИ
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Наименование)
ПО
    ОБЩИЕ

Посмотрим на символ точки с запятой ; в конце условия ГДЕ. В языке запросов 1С точка с запятой является разделителем пакетных запросов. Когда платформа видит ;, она считает, что первый запрос завершен. Секция ИТОГИ после точки с запятой воспринимается как синтаксическая ошибка или попытка начать новый некорректный запрос.

Важное правило: Если вы пишете один запрос, точку с запятой в его тексте ставить не нужно. Она используется только если вы создаете временные таблицы или выполняете несколько запросов за один вызов метода Запрос.Выполнить().

Особенности работы с итогами в коде

Когда мы используем предложение ИТОГИ, структура результата запроса перестает быть "плоской". Выборка данных в этом случае требует иного подхода в коде 1С. Рассмотрим, как правильно обходить результат с итогами:


РезультатЗапроса = Запрос.Выполнить();

// Для работы с ИТОГИ нужно указать тип обхода
ВыборкаОбщие = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Пока ВыборкаОбщие.Следующий() Цикл
    // Здесь мы получаем общие итоги (например, общее количество)
    Сообщить("Всего позиций: " + ВыборкаОбщие.Наименование);
    
    // Переходим к детальным записям внутри группы
    ВыборкаДетали = ВыборкаОбщие.Выбрать();
    Пока ВыборкаДетали.Следующий() Цикл
        Сообщить(" - Товар: " + ВыборкаДетали.Наименование);
    КонецЦикла;
КонецЦикла;

Рекомендации для стабильной работы запросов

Чтобы избежать пустого результата и ошибок в будущем, рекомендуем придерживаться следующих правил:

  1. Проверяйте массив на пустоту: Если в параметр &Список передать пустой массив, запрос не выдаст ошибку, но условие В(&Список) всегда будет ложным. Перед выполнением запроса делайте проверку Если Список.Количество() > 0 Тогда....
  2. Типизация параметров: Всегда следите за тем, чтобы тип данных реквизита в конфигураторе (Строка, Число, Ссылка) совпадал с типом данных, который вы передаете в УстановитьПараметр().
  3. Индексирование: Если вы часто ищете данные по полю Артикул, убедитесь, что для этого реквизита в конфигураторе включено свойство "Индексировать". Это значительно ускорит выполнение запроса на больших объемах данных.
  4. Использование СОКРП: В строковых полях могут быть лишние пробелы. При поиске по артикулу в запросе иногда полезно использовать функцию СОКРП(Номенклатура.Артикул), чтобы гарантировать точное совпадение.

Проанализировав данные ошибки, мы видим, что успешная работа с запросами в 1С требует не только знания синтаксиса SELECT/FROM/WHERE, но и глубокого понимания типов данных платформы 1С:Предприятие.

← На главную