Почему запрос 1С работает в консоли, но не возвращает результат в программном коде: разбираем типичные ошибки

Программист 1С v8.3 (Обычные формы) Управленческий учет Торговля и дистрибуция
← На главную

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

Ошибка 1: Использование предложения ГДЕ вместо параметров виртуальной таблицы

Проанализируем фрагмент кода из примера. Разработчик пытается получить остатки, накладывая условия в секции ГДЕ:


ВЫБРАТЬ
    МойСкладТашкентОстатки.КоличествоОстаток КАК КоличествоОстаток
ИЗ
    РегистрНакопления.МойСкладТашкент.Остатки КАК МойСкладТашкентОстатки
ГДЕ
    МойСкладТашкентОстатки.Номенклатура.Код = &ID
    И МойСкладТашкентОстатки.Основание.Дата <= &MOMENT

Разберем, почему это в корне неверно. Виртуальные таблицы (такие как Остатки или ОстаткиИОбороты) — это не просто таблицы в базе данных, а сложные механизмы, которые 1С формирует «на лету». Когда мы используем ГДЕ, система сначала рассчитывает вообще все остатки по всем товарам на текущий момент времени, и только потом начинает отсеивать лишнее по вашему условию. Это критически замедляет работу системы.

Правильный подход заключается в передаче фильтров напрямую в параметры виртуальной таблицы. Это позволяет СУБД выбрать только нужные записи еще на этапе формирования выборки. Наш запрос должен выглядеть так:


ВЫБРАТЬ
    МойСкладТашкентОстатки.КоличествоОстаток
ИЗ
    РегистрНакопления.МойСкладТашкент.Остатки(&Период, Номенклатура = &НоменклатураСсылка) КАК МойСкладТашкентОстатки

Ошибка 2: Поиск по коду или наименованию вместо Ссылки

Посмотрим на то, как устанавливаются параметры в коде автора: ITEM = ЭлементыФормы.Товар.Значение.Код;. Далее этот строковый код передается в запрос. Это классическая ошибка, которая часто приводит к тому, что «в консоли работает (где мы выбрали товар интерактивно), а в коде — нет».

Рассмотрим причины:

  1. Производительность: Поиск по строке (Код или Наименование) в базе данных выполняется на порядок медленнее, чем по внутреннему уникальному идентификатору (Ссылка).
  2. Надежность: Код может измениться, могут существовать дубли кодов, или в коде могут быть невидимые символы/пробелы.

Всегда передавайте в запрос объект типа СправочникСсылка. Выясним, как это сделать правильно в обычных формах:


// Плохо:
Запрос.УстановитьПараметр("ID", ЭлементыФормы.Товар.Значение.Код);

// Хорошо:
Запрос.УстановитьПараметр("НоменклатураСсылка", ЭлементыФормы.Товар.Значение);

Ошибка 3: Проблема даты и «Границы» периода

В 1С тип Дата включает время до секунды. Если вы передаете в параметр виртуальной таблицы остатков просто дату, например 01.01.2023 00:00:00, система покажет остатки на начало этой секунды. Если документ поступления был записан ровно в это же время, его движения не попадут в остаток.

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


МоментВремени = ЭлементыФормы.Дата.Значение;
ГраницаПериода = Новый Граница(МоментВремени, ВидГраницы.Включая);
Запрос.УстановитьПараметр("Период", ГраницаПериода);

Проанализируем ситуацию автора: использование MOMENT = Дата(ЭлементыФормы.Дата.Значение); избыточно, если реквизит уже имеет тип Дата, и может привести к непредсказуемым результатам при пустых значениях.

Ошибка 4: Лишние измерения (Основание) в таблице остатков

В тексте сообщения упоминается использование поля Основание.Дата в условии. Если поле Основание (например, документ поступления) не является Измерением регистра накопления, то в виртуальной таблице Остатки этого поля просто не будет. Если же оно является измерением, то остатки не будут суммироваться по товару в целом, а будут «висеть» в разрезе каждого конкретного документа.

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

Ошибка 5: Неправильный обход результата (ИТОГИ)

Автор использует в запросе конструкцию ИТОГИ СУММА(КоличествоОстаток) ПО ОБЩИЕ. В этом случае результат запроса представляет собой дерево, где на самом верхнем уровне находится одна строка с итоговой суммой.

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

Посмотрим на исправленный и оптимизированный алгоритм:


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

Резюме по решению проблемы

Разберем по шагам, что нужно проверить, если ваш код в 1С выдает не те результаты, что консоль запросов:

  1. Типы параметров: Убедитесь, что вы передаете в запрос Ссылку, а не Код или Наименование. Проверьте это в отладчике, остановившись на строке Запрос.УстановитьПараметр.
  2. Параметры виртуальных таблиц: Всегда выносите условия по времени (Период) и измерениям (Номенклатура, Склад) из секции ГДЕ в скобки виртуальной таблицы.
  3. Объект Граница: Если данные «теряются» именно на дату запроса, используйте Новый Граница(Дата, ВидГраницы.Включая).
  4. Данные формы: В обычных формах обращайтесь к ЭлементыФормы.ИмяЭлемента.Значение, но лучше — напрямую к реквизиту объекта или формы, к которому привязано поле.

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

← На главную