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