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