В процессе разработки на платформе 1С:Предприятие часто возникает ситуация, когда данные уже находятся в оперативной памяти (например, в таблице части формы или в коллекции ДанныеФормыКоллекция), но для дальнейшей обработки их нужно объединить с данными базы данных или быстро получить дополнительные реквизиты ссылок. Самым эффективным инструментом для этого является механизм запросов.
В этой статье мы подробно разберем, как правильно передать таблицу значений в запрос, как избежать типичных ошибок при работе с временными таблицами и какие альтернативные способы получения данных существуют в современных конфигурациях.
Это классический и наиболее универсальный способ. Если у нас есть объект ТаблицаЗначений (полученный, например, методом Выгрузить() из данных формы "Корзина"), мы можем поместить его во временную таблицу внутри запроса. Рассмотрим этот процесс по шагам.
Главная деталь, о которой часто забывают начинающие разработчики — необходимость использования объекта МенеджерВременныхТаблиц. Без него запрос не сможет "удержать" данные переданной таблицы во временном хранилище СУБД для последующего обращения к ним.
Проанализируем правильную структуру кода:
// 1. Подготовка исходной таблицы значений (на сервере)
ТЗ = Корзина.Выгрузить();
// 2. Создание запроса и инициализация менеджера временных таблиц
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
// 3. Текст запроса с помещением ТЗ во временную таблицу
Запрос.Текст =
"ВЫБРАТЬ
| ВременнаяТаблица.ЗаказПоставщику КАК ЗаказПоставщику
|ПОМЕСТИТЬ ВТЗаказы
|ИЗ
| &ВременнаяТаблица КАК ВременнаяТаблица
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТЗаказы.ЗаказПоставщику.Номер КАК Номер,
| ВТЗаказы.ЗаказПоставщику.Контрагент КАК Контрагент,
| ВТЗаказы.ЗаказПоставщику.Дата КАК Дата
|ИЗ
| ВТЗаказы КАК ВТЗаказы";
// 4. Передача ТЗ в качестве параметра
Запрос.УстановитьПараметр("ВременнаяТаблица", ТЗ);
// 5. Выполнение и получение результата
Выборка = Запрос.Выполнить().Выгрузить();
Важное замечание: Обращение к реквизитам через точку (например, ВТЗаказы.ЗаказПоставщику.Номер) в запросе порождает неявное левое соединение (LEFT JOIN) с таблицей документа. Если строк в таблице много, это может сказаться на производительности. Для оптимизации лучше выполнять явное соединение с основной таблицей документа по ссылке.
При работе с большими объемами данных или составными типами данных в колонках ТЗ, запрос может работать некорректно или медленно. Разберем, как улучшить наш подход.
Во-первых, платформа должна точно знать типы данных в колонках ТаблицаЗначений. Если таблица создается программно, всегда указывайте ОписаниеТипов. Если же данные выгружаются из формы, рекомендуется использовать оператор ВЫРАЗИТЬ в тексте запроса. Это помогает SQL-оптимизатору заранее определить, к каким физическим таблицам обращаться.
Во-вторых, если временная таблица будет участвовать в соединениях с другими таблицами базы данных, её обязательно нужно индексировать по ключевому полю.
Посмотрим на улучшенный пример кода:
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст =
"ВЫБРАТЬ
| ВЫРАЗИТЬ(ВременнаяТаблица.ЗаказПоставщику КАК Документ.ЗаказПоставщику) КАК ЗаказСсылка
|ПОМЕСТИТЬ ВТЗаказы
|ИЗ
| &ВременнаяТаблица КАК ВременнаяТаблица
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| Заказы.Номер,
| Заказы.Дата,
| Заказы.Контрагент
|ИЗ
| ВТЗаказы КАК ВТЗаказы
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ЗаказПоставщику КАК Заказы
| ПО ВТЗаказы.ЗаказСсылка = Заказы.Ссылка
|ИНДЕКСИРОВАТЬ ПО
| ЗаказСсылка";
Запрос.УстановитьПараметр("ВременнаяТаблица", ТЗ);
Результат = Запрос.Выполнить();
Если нам не нужно передавать дополнительные данные из строк таблицы (например, количество или цену, которые изменил пользователь в форме), а нужно просто получить реквизиты объектов по списку ссылок, можно использовать более простой метод — передачу массива в условие ГДЕ ... В (&Массив).
Этот способ избавляет от необходимости создавать МенеджерВременныхТаблиц и описывать структуру временной таблицы. Выясним, как это выглядит на практике:
// Выгружаем только колонку со ссылками в массив
МассивЗаказов = ТЗ.ВыгрузитьКолонку("ЗаказПоставщику");
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Заказ.Номер,
| Заказ.Дата,
| Заказ.Контрагент
|ИЗ
| Документ.ЗаказПоставщику КАК Заказ
|ГДЕ
| Заказ.Ссылка В (&МассивЗаказов)";
Запрос.УстановитьПараметр("МассивЗаказов", МассивЗаказов);
Выборка = Запрос.Выполнить().Выбрать();
Ограничение: Стоит учитывать, что при передаче очень больших массивов (свыше 10-20 тысяч элементов) СУБД может столкнуться с ограничениями на длину запроса. В таких случаях метод с временной таблицей (Метод 1) является более надежным.
Если ваша конфигурация разработана на базе современных типовых решений (например, УТ 11, ERP, БП 3.0), в ней наверняка присутствует БСП. Она предлагает готовые функции, которые позволяют получить значения реквизитов объектов без написания текста запроса вручную.
Функция ОбщегоНазначения.ЗначенияРеквизитовОбъектов принимает массив ссылок и строку с именами нужных полей. Это сокращает код до одной-двух строк:
// Получаем массив ссылок из таблицы
СписокСсылок = Корзина.ВыгрузитьКолонку("ЗаказПоставщику");
// Получаем соответствие (или таблицу) с данными
ДанныеЗаказов = ОбщегоНазначения.ЗначенияРеквизитовОбъектов(СписокСсылок, "Номер, Контрагент, Дата");
Такой подход делает код более читаемым и снижает вероятность ошибок в синтаксисе запроса.
ПОМЕСТИТЬ) вы не переименовали колонку или во втором запросе обращаетесь к имени, которого нет в ТЗ. Всегда проверяйте соответствие имен в конструкции ВЫБРАТЬ ... КАК ИмяПоля.Запрос и ТаблицаЗначений доступны только на сервере. Если вы находитесь в контексте клиентской процедуры формы, данные коллекции ДанныеФормыКоллекция нужно передать на сервер, там выполнить Выгрузить() и только потом запускать запрос.NULL или привести к непредвиденным результатам в соединениях. Используйте ВНУТРЕННЕЕ СОЕДИНЕНИЕ, если пустые значения вам не нужны в результате.Подводя итог, можно сказать: для простых задач получения данных по списку идеально подходит массив в параметре запроса или функции БСП. Если же задача сложная, включает много условий и требует связи данных из формы с данными БД — используйте временные таблицы с обязательной инициализацией менеджера временных таблиц.