Ситуация, когда сложный запрос безупречно отрабатывает в консоли запросов, но при выполнении в модуле формы или обработки возвращает пустую выборку, является классической проблемой при разработке на платформе 1С:Предприятие 8.3. В данной статье мы подробно разберем конкретный кейс из практики программиста БП 3.0, проанализируем причины возникновения таких ошибок и рассмотрим лучшие практики написания кода, которые помогут избежать подобных проблем в будущем.
Проанализируем исходную ситуацию. Программист столкнулся с тем, что отчет в конфигурации «Бухгалтерия предприятия 3.0» не выводит данные. В коде выполнялся поиск дополнительных сведений (Водитель и Автомобиль) и их последующее использование в сложном запросе с левыми соединениями. Рассмотрим фрагмент кода, в котором была допущена критическая ошибка:
// Фрагмент кода из запроса автора
| ГДЕ
| (ВложенныйЗапрос.Водитель В (&Водитель)
| ИЛИ &Водитель = ЗНАЧЕНИЕ(Справочник.ФизическиеЛица.ПустаяСсылка))
| И (ВложенныйЗапрос.Автомобиль В (&Водитель) // ОШИБКА ЗДЕСЬ!
| ИЛИ &Автомобиль = ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка))
Как выяснилось в ходе обсуждения, причиной пустого результата стала обычная опечатка. В условии фильтрации по автомобилю использовался параметр &Водитель вместо &Автомобиль. Поскольку типы данных водителя (физическое лицо) и автомобиля (в данном случае справочник Склады или транспортные средства) не пересекаются, пересечение множеств по двум разным полям с одним и тем же значением параметра всегда давало пустой результат.
Важный вывод: В консоли запросов мы заполняем параметры вручную и видим их значения наглядно. В коде, особенно при использовании копирования похожих строк (copy-paste), глаз «замыливается», и такие логические ошибки пропускаются. Всегда проверяйте соответствие имен переменных в методе УстановитьПараметр и в тексте самого запроса.
Если вы проверили имена параметров и они верны, но результат всё равно пустой, следует проанализировать ситуацию по шагам. Рассмотрим наиболее частые причины:
УстановитьПривилегированныйРежим(Истина).УстановитьПараметр строго соответствовал типу поля в БД. Например, если поле имеет составной тип, иногда требуется явное приведение в запросе через оператор ВЫРАЗИТЬ.&Водитель передается пустой Массив или пустой СписокЗначений, условие Поле В (&Параметр) всегда будет ложным (Ложь). Это часто приводит к тому, что вся выборка исчезает.НайтиПоНаименованию. Это крайне опасный метод. Если в базе есть два элемента с одинаковым именем (в разных группах) или в имени затесался лишний пробел, функция может вернуть не то свойство, которое вы ожидали, или пустую ссылку.Давайте разберем, как сделать код автора более надежным и производительным. Работа с регистром сведений ДополнительныеСведения через несколько левых соединений — это ресурсоемкая операция. Рассмотрим более правильный подход с использованием временных таблиц.
Во-первых, откажемся от поиска свойств в циклах и по наименованию. Во-вторых, воспользуемся временной таблицей для хранения среза нужных нам данных. Посмотрим на пример оптимизированного запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДополнительныеСведения.Объект КАК Объект,
| ДополнительныеСведения.Значение КАК Значение,
| ДополнительныеСведения.Свойство КАК Свойство
|ПОМЕСТИТЬ ВТ_ДопСведения
|ИЗ
| РегистрСведений.ДополнительныеСведения КАК ДополнительныеСведения
|ГДЕ
| ДополнительныеСведения.Свойство В(&СписокСвойств);
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| Счет.Ссылка КАК Ссылка,
| Счет.Организация КАК Организация,
| ЕСТЬNULL(ДопВод.Значение, ЗНАЧЕНИЕ(Справочник.ФизическиеЛица.ПустаяСсылка)) КАК Водитель,
| ЕСТЬNULL(ДопАвт.Значение, ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)) КАК Автомобиль
|ИЗ
| Документ.СчетНаОплатуПокупателю КАК Счет
| ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ДопСведения КАК ДопВод
| ПО Счет.Ссылка = ДопВод.Объект
| И (ДопВод.Свойство = &СвойствоВодитель)
| ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ДопСведения КАК ДопАвт
| ПО Счет.Ссылка = ДопАвт.Объект
| И (ДопАвт.Свойство = &СвойствоАвтомобиль)
|ГДЕ
| Счет.Дата МЕЖДУ &ДатаНач И &ДатаКон
| И (&Организация = ЗНАЧЕНИЕ(Справочник.Организации.ПустаяСсылка) ИЛИ Счет.Организация = &Организация)";
// Заполнение параметров...
В данном примере мы сначала выбираем все записи из регистра сведений по нужным нам свойствам во временную таблицу ВТ_ДопСведения. Это позволяет SQL-серверу эффективнее построить план запроса, так как объем данных во временной таблице будет значительно меньше, чем в основном регистре.
Если вы столкнулись с проблемой «в консоли работает, а в коде — нет», выполните следующие действия:
Неопределено или NULL, если она не инициализирована. В консоли мы обычно выбираем конкретную пустую ссылку нужного типа. Убедитесь, что ваши параметры в коде — это именно ссылки (объекты типа СправочникСсылка), а не другие типы.В ИЕРАРХИИ работает медленнее, чем просто В. Если вы передаете пустую ссылку в В ИЕРАРХИИ, результат может зависеть от версии платформы и настроек СУБД, хотя чаще всего 1С обрабатывает это корректно.Поскольку работа ведется в конфигурации «Бухгалтерия предприятия 3.0», которая построена на базе «Библиотеки стандартных подсистем» (БСП), для получения дополнительных сведений эффективнее использовать штатные механизмы. Рассмотрим, как это можно сделать без написания собственных тяжелых запросов к регистру ДополнительныеСведения.
Проанализируем программный интерфейс БСП. Для работы со свойствами существует общий модуль УправлениеСвойствами. Вместо ручного соединения таблиц, можно получить значения свойств для списка объектов одним вызовом функции, которая уже оптимизирована под конкретную версию платформы и учитывает кэширование данных.
Резюме: Основная причина расхождений между консолью и кодом чаще всего кроется в невнимательности при заполнении параметров (опечатки) или в специфике прав доступа (RLS). Использование временных таблиц и отказ от поиска по наименованию сделают ваш код не только более быстрым, но и гораздо более устойчивым к ошибкам.