При изучении механизмов работы с запросами в 1С:Предприятие 8 начинающие разработчики часто сталкиваются с ситуацией, когда код кажется верным, массив параметров заполнен данными, но результат выполнения запроса остается пустым. В данной статье мы подробно разберем, почему так происходит, проанализируем ошибки сопоставления типов данных и выясним, как правильно работать с условиями в запросах и секцией ИТОГИ.
Рассмотрим типичную ситуацию, представленную в вопросе. Программист пытается найти товары по их артикулам, используя условие В(&СписокАртикулов). Давайте проанализируем исходный код:
Запрос.Текст = "ВЫБРАТЬ
| Номенклатура.Код,
| Номенклатура.Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Артикул В(&СписокАртикулов)";
МассивСтр = Новый Массив;
МассивСтр.Добавить(Справочники.Номенклатура.НайтиПоРеквизиту("Артикул","K9543NT"));
Запрос.УстановитьПараметр("СписокАртикулов", МассивСтр);
Проблема заключается в том, что поле Номенклатура.Артикул в базе данных имеет тип Строка. Однако метод НайтиПоРеквизиту() возвращает объект типа СправочникСсылка.Номенклатура. В языке запросов 1С (как и в большинстве СУБД) невозможно напрямую сравнить уникальный идентификатор (ссылку) со строкой текста. Даже если в этой ссылке "внутри" записан нужный артикул, для системы это разные типы данных. В итоге условие ГДЕ всегда возвращает ЛОЖЬ, и результат запроса оказывается пустым.
Как исправить: Существует два способа решения в зависимости от того, что именно вы хотите найти.
НайтиПоРеквизиту(). Это также значительно повысит производительность, так как исключит лишние обращения к базе данных перед самим запросом.Ссылка.Проанализируем правильный вариант кода для поиска по строковым артикулам:
МассивАртикулов = Новый Массив;
МассивАртикулов.Добавить("K9543NT");
МассивАртикулов.Добавить("P0130TN");
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ Артикул ИЗ Справочник.Номенклатура ГДЕ Артикул В(&СписокАртикулов)";
Запрос.УстановитьПараметр("СписокАртикулов", МассивАртикулов);
Выясним еще одну важную деталь. В процессе обсуждения возник вариант: найти ссылку по артикулу, чтобы потом у этой ссылки снова взять артикул и положить его в массив. Рассмотрим этот пример:
// Плохой пример: избыточное действие
Ссылка = Справочники.Номенклатура.НайтиПоРеквизиту("Артикул", "K9543NT");
МассивСтр.Добавить(Ссылка.Артикул);
Такой подход крайне неэффективен. Метод НайтиПоРеквизиту — это отдельный скрытый запрос к базе данных. Если вы уже знаете строку артикула, нет никакого смысла "спрашивать" у базы ссылку на товар только для того, чтобы снова получить ту же самую строку артикула. Всегда стремитесь минимизировать количество обращений к серверу БД.
Второй важный аспект проблемы касается синтаксиса запроса при использовании агрегатных функций и итогов. Разберем пример запроса, который выдавал ошибку или некорректный результат:
ВЫБРАТЬ
Номенклатура.Код,
Номенклатура.Наименование КАК Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.ЭтоГруппа = ЛОЖЬ И Номенклатура.Ссылка В(&СписокАртикулов);
ИТОГИ
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Наименование)
ПО
ОБЩИЕ
Посмотрим на символ точки с запятой ; в конце условия ГДЕ. В языке запросов 1С точка с запятой является разделителем пакетных запросов. Когда платформа видит ;, она считает, что первый запрос завершен. Секция ИТОГИ после точки с запятой воспринимается как синтаксическая ошибка или попытка начать новый некорректный запрос.
Важное правило: Если вы пишете один запрос, точку с запятой в его тексте ставить не нужно. Она используется только если вы создаете временные таблицы или выполняете несколько запросов за один вызов метода Запрос.Выполнить().
Когда мы используем предложение ИТОГИ, структура результата запроса перестает быть "плоской". Выборка данных в этом случае требует иного подхода в коде 1С. Рассмотрим, как правильно обходить результат с итогами:
РезультатЗапроса = Запрос.Выполнить();
// Для работы с ИТОГИ нужно указать тип обхода
ВыборкаОбщие = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока ВыборкаОбщие.Следующий() Цикл
// Здесь мы получаем общие итоги (например, общее количество)
Сообщить("Всего позиций: " + ВыборкаОбщие.Наименование);
// Переходим к детальным записям внутри группы
ВыборкаДетали = ВыборкаОбщие.Выбрать();
Пока ВыборкаДетали.Следующий() Цикл
Сообщить(" - Товар: " + ВыборкаДетали.Наименование);
КонецЦикла;
КонецЦикла;
Чтобы избежать пустого результата и ошибок в будущем, рекомендуем придерживаться следующих правил:
&Список передать пустой массив, запрос не выдаст ошибку, но условие В(&Список) всегда будет ложным. Перед выполнением запроса делайте проверку Если Список.Количество() > 0 Тогда....УстановитьПараметр().Артикул, убедитесь, что для этого реквизита в конфигураторе включено свойство "Индексировать". Это значительно ускорит выполнение запроса на больших объемах данных.СОКРП(Номенклатура.Артикул), чтобы гарантировать точное совпадение.Проанализировав данные ошибки, мы видим, что успешная работа с запросами в 1С требует не только знания синтаксиса SELECT/FROM/WHERE, но и глубокого понимания типов данных платформы 1С:Предприятие.