Почему не работает отбор в запросе 1С: разбираем ошибки типизации и передачи параметров из формы

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

Разработка отчетов и обработок в системе «1С:Предприятие 8» часто начинается с создания экранных форм, где пользователь вводит критерии отбора. Однако начинающие разработчики, особенно переходящие из других сред разработки (таких как Xcode или Android Studio), часто сталкиваются с ситуацией: данные на форме есть, код написан, но запрос выдает либо пустой результат, либо игнорирует условия отбора. Проанализируем типичную ситуацию, разберем причины ошибок и научимся правильно работать с типами данных и периодами.

Разбор первой ошибки: синтаксис параметров запроса

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


Запрос.Текст = "ВЫБРАТЬ
| ЗаказКлиента.Номер КАК Номер,
| ЗаказКлиента.СуммаДокумента КАК СуммаДокумента
|ИЗ
| Документ.ЗаказКлиента КАК ЗаказКлиента
|ГДЕ
| ЗаказКлиента.СуммаДокумента = СуммаДокумента"; // Ошибка здесь!

В языке запросов 1С существует четкое различие между полями таблиц базы данных и внешними параметрами, которые мы передаем в запрос. Чтобы система поняла, что СуммаДокумента — это переменная, переданная через метод УстановитьПараметр, перед ней обязательно должен стоять символ амперсанда &.

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

Правильный вариант написания условия:


|ГДЕ
| ЗаказКлиента.СуммаДокумента = &СуммаДокумента";

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

Даже после исправления синтаксиса отбор может не заработать, если тип данных реквизита на форме не совпадает с типом данных в базе. В нашем примере реквизит Сумма на форме имел тип Строка. Рассмотрим, почему это критично для 1С.

В отличие от языков с динамической типизацией или неявным приведением типов (где строка "100" может автоматически стать числом при сравнении), механизм запросов 1С взаимодействует напрямую с СУБД (SQL). Для базы данных число 100 и строка "100" — это принципиально разные объекты. Сравнение Число = Строка всегда будет возвращать Ложь.

Выясним, как это исправить. Нам необходимо зайти в Конфигуратор, открыть форму обработки, найти в списке реквизитов поле Сумма и в его свойствах изменить тип на Число. Также важно установить правильную точность (обычно 2 знака после запятой для денежных сумм), чтобы она соответствовала точности поля СуммаДокумента в документе ЗаказКлиента.

Оптимизация работы с контекстом: Объект и РеквизитФормыВЗначение

Проанализируем еще один важный аспект кода — использование функции РеквизитФормыВЗначение. В исходном коде автора мы видим:


Обработка = РеквизитФормыВЗначение("Объект");
Макет = Обработка.ПолучитьМакет("Макет");

Это действие необходимо только в том случае, если вам нужно вызвать экспортный метод или получить макет, который хранится непосредственно в объекте метаданных (обработке или отчете). Однако, если вам нужно просто получить значение суммы, введенное пользователем, нет необходимости "превращать" данные формы в тяжеловесный объект базы данных. На сервере значения реквизитов формы доступны напрямую через точку от переменной Объект.

Разберем, как сократить код и повысить производительность:


&НаСервере
Процедура ПоказатьНаСервере(ТабДок)
    // Мы можем напрямую обращаться к данным формы
    ТекущаяСумма = Объект.Сумма; 
    
    Запрос = Новый Запрос;
    Запрос.Текст = "... ГДЕ ЗаказКлиента.СуммаДокумента = &ПараметрСумма";
    Запрос.УстановитьПараметр("ПараметрСумма", ТекущаяСумма);
    // ... дальнейшая обработка
КонецПроцедуры

Работа с периодами в 1С: выборка данных за отрезок времени

Часто возникает задача ограничить выборку не одним значением, а временным интервалом (начало и конец периода). Рассмотрим наиболее эффективные способы реализации этой задачи.

1. Использование объекта СтандартныйПериод

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


ДатаНачала = Объект.ПериодОтчета.ДатаНачала;
ДатаОкончания = Объект.ПериодОтчета.ДатаОкончания;

2. Важность функции КОНЕЦПЕРИОДА

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


Запрос.Текст = "ВЫБРАТЬ ... ГДЕ ЗаказКлиента.Дата МЕЖДУ &Начало И КОНЕЦПЕРИОДА(&Конец, ДЕНЬ)";
Запрос.УстановитьПараметр("Начало", ДатаНачала);
Запрос.УстановитьПараметр("Конец", ДатаОкончания);

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

  1. Проверяем типы данных: Убеждаемся, что реквизит на форме (например, Сумма или Дата) имеет тот же тип, что и поле в базе данных.
  2. Используем параметры правильно: В тексте запроса всегда ставим & перед именем параметра.
  3. Устанавливаем параметры: Обязательно вызываем Запрос.УстановитьПараметр("ИмяБезАмперсанда", Значение).
  4. Обрабатываем границы периода: Всегда используем КОНЕЦПЕРИОДА для верхней границы даты, чтобы не потерять данные за последний день.
  5. Выводим результат: Используем ТабличныйДокумент и Макет для визуализации данных пользователю.

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

← На главную