Разработка и Конфигурация · 11 мин
Как сделать запрос из таблицы значений в 1С
Как сделать запрос из таблицы значений в 1С: передача через параметр, МенеджерВременныхТаблиц, ПОМЕСТИТЬ, типизация колонок и типичные ошибки при работе с запросами.
Таблица значений — один из самых удобных способов передать в запрос 1С набор данных, сформированный программно: список номенклатуры из обработки, результат расчёта, данные, загруженные из файла. Платформа позволяет передать такую таблицу параметром запроса и обращаться к ней в тексте запроса почти как к обычной таблице базы данных.
Задача решается двумя основными способами: передача таблицы значений непосредственно как параметра запроса с последующим помещением во временную таблицу, либо через менеджер временных таблиц с методом ПоместитьТаблицуЗначений. Оба подхода рабочие, но различаются по удобству, производительности и требованиям к типизации колонок.
Ниже разобраны оба варианта с полным кодом, требования к подготовке таблицы значений, типичные ошибки и способы проверить, что запрос отработал корректно.
Как платформа передаёт таблицу значений в запрос
Когда вы устанавливаете параметр запроса значением типа «ТаблицаЗначений», платформа сериализует её и передаёт на сервер СУБД как набор строк. В тексте запроса такой параметр можно использовать в конструкции ВЫБРАТЬ ... ИЗ &ИмяПараметра — поля таблицы становятся доступны по именам колонок.
Ключевое ограничение: колонки таблицы значений должны иметь явно заданные типы. Если колонка создана без типизации (например, просто ТЗ.Колонки.Добавить("Номенклатура") без второго параметра), платформа не сможет сформировать корректную структуру на стороне СУБД, и запрос завершится ошибкой. Поэтому типизация через ОписаниеТипов — обязательный шаг подготовки.
Способ 1: параметр запроса и конструкция ПОМЕСТИТЬ
Самый распространённый вариант — передать таблицу параметром и в первом же пакете запроса поместить её во временную таблицу. Дальше с ней можно соединяться с реальными таблицами базы.
Пример полного кода:
// Подготовка таблицы значений с типизацией
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
СтрокаТЗ = ТЗ.Добавить();
СтрокаТЗ.Номенклатура = Справочники.Номенклатура.НайтиПоКоду("000000001");
СтрокаТЗ.Количество = 10;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.УстановитьПараметр("ТаблицаТоваров", ТЗ);
Запрос.Текст =
"ВЫБРАТЬ
| ТаблицаТоваров.Номенклатура КАК Номенклатура,
| ТаблицаТоваров.Количество КАК Количество
|ПОМЕСТИТЬ ВТ_Товары
|ИЗ
| &ТаблицаТоваров КАК ТаблицаТоваров
|;
|
|ВЫБРАТЬ
| ВТ.Номенклатура КАК Номенклатура,
| ВТ.Количество КАК Количество,
| ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток
|ИЗ
| ВТ_Товары КАК ВТ
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
| ПО ВТ.Номенклатура = Остатки.Номенклатура";
Результат = Запрос.Выполнить().Выгрузить();
Обратите внимание на два момента. Во-первых, менеджер временных таблиц нужно создать явно, иначе временная таблица ВТ_Товары не сохранится между пакетами. Во-вторых, псевдонимы полей лучше задавать сразу — это упрощает чтение последующих запросов.
- 1Создайте таблицу значений и задайте типы колонок через ОписаниеТипов
- 2Заполните таблицу строками
- 3Создайте Запрос и при необходимости МенеджерВременныхТаблиц
- 4Установите параметр запроса значением таблицы
- 5В тексте запроса поместите параметр во временную таблицу через ПОМЕСТИТЬ
- 6Используйте временную таблицу в соединениях с таблицами базы
- 7Выполните запрос и проверьте результат методом Выгрузить или Выбрать
Способ 2: МенеджерВременныхТаблиц и ПоместитьТаблицуЗначений
Второй подход — поместить таблицу значений во временную таблицу напрямую, минуя текст запроса. Для этого у объекта МенеджерВременныхТаблиц есть метод ПоместитьТаблицуЗначений(ТаблицаЗначений, ИмяТаблицы).
МенеджерВТ = Новый МенеджерВременныхТаблиц;
МенеджерВТ.ПоместитьТаблицуЗначений(ТЗ, "ВТ_Товары");
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос.Текст =
"ВЫБРАТЬ
| ВТ.Номенклатура КАК Номенклатура,
| ВТ.Количество КАК Количество
|ИЗ
| ВТ_Товары КАК ВТ";
Результат = Запрос.Выполнить().Выгрузить();
Этот способ удобен, когда одна и та же таблица значений используется в нескольких независимых запросах: не нужно каждый раз передавать параметр и писать пакет с ПОМЕСТИТЬ. Имена колонок временной таблицы совпадают с именами колонок исходной таблицы значений.
Требование к типизации здесь ещё строже: метод ПоместитьТаблицуЗначений формирует структуру временной таблицы по типам колонок, и нетипизированная колонка приведёт к ошибке на этапе вызова метода, а не запроса.
Сравнение вариантов
Универсально, весь код в одном месте. Подходит, когда таблица нужна в одном запросе. Минус — лишний пакет в тексте запроса.
Удобно при повторном использовании таблицы в нескольких запросах. Минус — структура временной таблицы менее очевидна из текста запроса, отладка сложнее.
Если данные можно получить запросом к базе, лучше не выгружать их в ТЗ вообще — соединяйтесь напрямую, это быстрее.
Требования к подготовке таблицы значений
Перед передачей в запрос проверьте таблицу по нескольким пунктам. Все колонки, участвующие в запросе, должны иметь явный тип. Для ссылочных типов указывайте конкретный вид ссылки — СправочникСсылка.Номенклатура, а не составной тип «любая ссылка»: составные типы замедляют соединения и могут приводить к неэффективным планам запроса на СУБД.
Для числовых колонок задавайте разумную разрядность через КвалификаторыЧисла, для строк — длину через КвалификаторыСтроки. Строка неограниченной длины в запросе не может участвовать в соединениях и группировках — платформа выдаст ошибку.
Если таблица значений получена выгрузкой результата другого запроса (Выгрузить()), типы колонок обычно уже заданы корректно, и дополнительная подготовка не нужна. Проблемы чаще возникают с таблицами, собранными вручную или загруженными из внешних источников.
Как проверить результат и отладить запрос
Самый простой способ убедиться, что временная таблица сформирована, — выполнить отдельный запрос ВЫБРАТЬ * ИЗ ВТ_Товары с тем же менеджером временных таблиц и выгрузить результат. Количество строк должно совпадать с количеством строк исходной таблицы значений.
Для отладки удобна консоль запросов (внешняя обработка): она показывает временные таблицы, позволяет выполнить запрос по шагам и увидеть содержимое каждого пакета. Если запрос возвращает пустой результат, проверьте в первую очередь соединения: несовпадение типов ссылки или лишние пробелы в строковых ключах — частая причина «невидимых» несовпадений.
Как проверить результат
Совпадает с числом строк исходной ТЗ
Меньше или ноль — проверяйте типизацию колонок и заполнение ТЗ
Совпадающие ссылки дают заполненные поля
Все поля соединения NULL — разные типы ссылок или пустые значения в ТЗ
Поля имеют ожидаемые типы (ссылка, число)
Поле имеет составной тип или строку неограниченной длины
Типичные ошибки и их причины
Самая частая ошибка — «Неверные параметры в операции сравнения» или падение запроса из-за нетипизированной колонки. Лечится явным указанием ОписаниеТипов при создании колонки. Вторая по частоте — обращение к временной таблице в другом запросе без общего менеджера временных таблиц: каждый объект Запрос без явно назначенного менеджера создаёт свой собственный, и временные таблицы между ними не видны.
Ещё одна проблема — имена колонок, совпадающие с зарезервированными словами языка запросов (например, «Период», «Номер» обычно допустимы, но лучше давать осмысленные уникальные имена). Также не забывайте, что таблица значений с колонкой типа «ХранилищеЗначения» или «Картинка» не может быть передана в запрос осмысленно — такие колонки следует исключить.
Когда таблицу значений лучше не использовать
Передача таблицы значений в запрос оправдана, когда данные сформированы вне базы: загружены из файла, получены из веб-сервиса, рассчитаны программно. Если же источник данных — сама информационная база (справочники, документы, регистры), выгружать их в таблицу значений и передавать обратно в запрос бессмысленно: прямое соединение в одном запросе всегда быстрее и проще.
Для фильтрации по списку значений также не обязательно строить таблицу: достаточно передать массив или список значений параметром и использовать условие ГДЕ Номенклатура В (&СписокНоменклатуры). Таблица значений нужна именно тогда, когда передаётся несколько связанных колонок — например, пары «номенклатура + количество + цена».
Часто задаваемые вопросы
Можно ли передать таблицу значений в запрос в СКД?
Да, но иначе: в СКД таблицу значений подключают как внешний набор данных через объект «ТаблицаЗначений» в схеме компоновки и заполняют в коде при формировании отчёта через КомпоновщикМакета и ПроцессорКомпоновкиДанных с коллекцией внешних наборов. Параметром запроса внутри СКД таблицу передать нельзя.
Почему запрос с параметром-таблицей работает медленно?
Чаще всего из-за составных типов колонок, большого объёма таблицы или отсутствия индексов у временной таблицы. Для больших таблиц добавьте во временную таблицу индекс конструкцией ИНДЕКСИРОВАТЬ ПО по полям соединения — это заметно ускоряет последующие соединения.
Можно ли изменить переданную таблицу внутри запроса?
Нет, параметр доступен только на чтение. Но вы можете поместить данные во временную таблицу и дальше обрабатывать их последующими пакетами запроса: фильтровать, группировать, соединять, создавая новые временные таблицы.
Что делать, если колонка содержит значения разных типов?
Приведите значения к одному типу до передачи в запрос. Если это невозможно, задайте составной тип в ОписаниеТипов, но учтите, что соединения по таким полям будут медленнее и могут требовать явного приведения через ВЫРАЗИТЬ(... КАК ...) в тексте запроса.
Как передать таблицу значений в запрос на управляемых формах с сервера?
Точно так же — таблица значений создаётся и заполняется в серверной процедуре, передаётся параметром запроса. Ограничение: таблица значений не сериализуется между клиентом и сервером напрямую, поэтому все операции с ней выполняйте в серверном контексте.
Что важно запомнить
Таблица значений передаётся в запрос параметром и помещается во временную таблицу через ПОМЕСТИТЬ либо методом МенеджерВТ.ПоместитьТаблицуЗначений. Обязательна типизация колонок через ОписаниеТипов и общий менеджер временных таблиц для всех связанных запросов. Если данные уже есть в базе — используйте прямой запрос без промежуточной таблицы значений.