Разработка отчетов и обработок в системе «1С:Предприятие 8» часто начинается с создания экранных форм, где пользователь вводит критерии отбора. Однако начинающие разработчики, особенно переходящие из других сред разработки (таких как Xcode или Android Studio), часто сталкиваются с ситуацией: данные на форме есть, код написан, но запрос выдает либо пустой результат, либо игнорирует условия отбора. Проанализируем типичную ситуацию, разберем причины ошибок и научимся правильно работать с типами данных и периодами.
Рассмотрим фрагмент кода, в котором разработчик пытается ограничить выборку документов по сумме. В тексте запроса была допущена критическая ошибка в написании условия ГДЕ. Проанализируем код:
Запрос.Текст = "ВЫБРАТЬ
| ЗаказКлиента.Номер КАК Номер,
| ЗаказКлиента.СуммаДокумента КАК СуммаДокумента
|ИЗ
| Документ.ЗаказКлиента КАК ЗаказКлиента
|ГДЕ
| ЗаказКлиента.СуммаДокумента = СуммаДокумента"; // Ошибка здесь!
В языке запросов 1С существует четкое различие между полями таблиц базы данных и внешними параметрами, которые мы передаем в запрос. Чтобы система поняла, что СуммаДокумента — это переменная, переданная через метод УстановитьПараметр, перед ней обязательно должен стоять символ амперсанда &.
Если написать ЗаказКлиента.СуммаДокумента = СуммаДокумента, платформа воспримет это как сравнение поля таблицы с самим собой (что всегда истинно для непустых значений) или попытается найти другое поле с таким же именем в этой же таблице. В результате отбор просто не сработает, и в отчет попадут все записи.
Правильный вариант написания условия:
|ГДЕ
| ЗаказКлиента.СуммаДокумента = &СуммаДокумента";
Даже после исправления синтаксиса отбор может не заработать, если тип данных реквизита на форме не совпадает с типом данных в базе. В нашем примере реквизит Сумма на форме имел тип Строка. Рассмотрим, почему это критично для 1С.
В отличие от языков с динамической типизацией или неявным приведением типов (где строка "100" может автоматически стать числом при сравнении), механизм запросов 1С взаимодействует напрямую с СУБД (SQL). Для базы данных число 100 и строка "100" — это принципиально разные объекты. Сравнение Число = Строка всегда будет возвращать Ложь.
Выясним, как это исправить. Нам необходимо зайти в Конфигуратор, открыть форму обработки, найти в списке реквизитов поле Сумма и в его свойствах изменить тип на Число. Также важно установить правильную точность (обычно 2 знака после запятой для денежных сумм), чтобы она соответствовала точности поля СуммаДокумента в документе ЗаказКлиента.
Проанализируем еще один важный аспект кода — использование функции РеквизитФормыВЗначение. В исходном коде автора мы видим:
Обработка = РеквизитФормыВЗначение("Объект");
Макет = Обработка.ПолучитьМакет("Макет");
Это действие необходимо только в том случае, если вам нужно вызвать экспортный метод или получить макет, который хранится непосредственно в объекте метаданных (обработке или отчете). Однако, если вам нужно просто получить значение суммы, введенное пользователем, нет необходимости "превращать" данные формы в тяжеловесный объект базы данных. На сервере значения реквизитов формы доступны напрямую через точку от переменной Объект.
Разберем, как сократить код и повысить производительность:
&НаСервере
Процедура ПоказатьНаСервере(ТабДок)
// Мы можем напрямую обращаться к данным формы
ТекущаяСумма = Объект.Сумма;
Запрос = Новый Запрос;
Запрос.Текст = "... ГДЕ ЗаказКлиента.СуммаДокумента = &ПараметрСумма";
Запрос.УстановитьПараметр("ПараметрСумма", ТекущаяСумма);
// ... дальнейшая обработка
КонецПроцедуры
Часто возникает задача ограничить выборку не одним значением, а временным интервалом (начало и конец периода). Рассмотрим наиболее эффективные способы реализации этой задачи.
1. Использование объекта СтандартныйПериод
Для удобства пользователя рекомендуется добавить на форму реквизит с типом СтандартныйПериод. Это даст стандартную кнопку выбора периода (месяц, квартал, год). В коде мы получим доступ к двум датам:
ДатаНачала = Объект.ПериодОтчета.ДатаНачала;
ДатаОкончания = Объект.ПериодОтчета.ДатаОкончания;
2. Важность функции КОНЕЦПЕРИОДА
При сравнении дат в запросе нужно помнить, что дата в 1С всегда включает время. Если пользователь выбрал период по 31.10.2023, то по умолчанию время будет 00:00:00. Документы, созданные в течение дня 31 октября, не попадут в выборку. Чтобы избежать этого, используем встроенную функцию запроса:
Запрос.Текст = "ВЫБРАТЬ ... ГДЕ ЗаказКлиента.Дата МЕЖДУ &Начало И КОНЕЦПЕРИОДА(&Конец, ДЕНЬ)";
Запрос.УстановитьПараметр("Начало", ДатаНачала);
Запрос.УстановитьПараметр("Конец", ДатаОкончания);
Сумма или Дата) имеет тот же тип, что и поле в базе данных.& перед именем параметра.Запрос.УстановитьПараметр("ИмяБезАмперсанда", Значение).КОНЕЦПЕРИОДА для верхней границы даты, чтобы не потерять данные за последний день.ТабличныйДокумент и Макет для визуализации данных пользователю.Соблюдение этих простых правил позволит избежать большинства ошибок при работе с запросами и сделает ваш код надежным и понятным для других разработчиков. Помните, что 1С — это система со строгой типизацией, где аккуратность в определении реквизитов формы является залогом корректной работы бизнес-логики.