К статье
Практический материал

Разработка и Конфигурация · 10 мин

Как передать таблицу в запрос в 1С

Как передать таблицу значений или табличную часть в запрос 1С через параметр, использовать конструкцию ПОМЕСТИТЬ и временные таблицы. Примеры кода и ошибки.

Передача таблицы в запрос — типовая задача при разработке на платформе 1С:Предприятие 8. Таблица значений или табличная часть документа передаётся в объект «Запрос» как параметр, после чего её можно поместить во временную таблицу и использовать в соединениях, отборах и группировках наравне с таблицами базы данных.

Такой приём применяется, когда нужно отфильтровать данные по заранее подготовленному списку (например, по списку номенклатуры или контрагентов), соединить данные документа с регистрами, рассчитать остатки только по выбранным позициям или выполнить пакетную обработку без обхода строк в цикле. Запрос с временной таблицей почти всегда работает быстрее, чем перебор строк с обращением к базе на каждой итерации.

Ниже разобраны способы передачи таблицы в запрос, требования к структуре колонок, работа с менеджером временных таблиц, типичные ошибки и ограничения платформы.

Какие таблицы можно передать в запрос

В качестве параметра запроса платформа принимает два типа табличных данных: объект «ТаблицаЗначений», сформированный программно, и табличную часть объекта (документа, справочника, обработки), переданную через метод Выгрузить(). В обоих случаях в запрос попадает набор строк с именованными колонками.

Ключевое требование — колонки должны иметь явно заданные типы. Если таблица значений создана кодом, колонки добавляются через Колонки.Добавить() с указанием ОписаниеТипов. Колонка без типа или с неопределённым составом типов может вызвать ошибку при выгрузке во временную таблицу, особенно если в ней встречаются значения NULL или пустые ссылки разных видов.

Базовый способ: параметр и конструкция ПОМЕСТИТЬ

Стандартная схема состоит из трёх шагов: подготовить таблицу, установить её как параметр запроса, в первом пакете запроса выбрать данные из параметра и поместить во временную таблицу. Далее временная таблица доступна во всех последующих пакетах этого же запроса.

Запрос = Новый Запрос;

Запрос.УстановитьПараметр("ТаблицаТоваров", ТаблицаТоваров);

Запрос.Текст =

"ВЫБРАТЬ

| Таб.Номенклатура КАК Номенклатура,

| Таб.Количество КАК Количество

|ПОМЕСТИТЬ ВТ_Товары

|ИЗ

| &ТаблицаТоваров КАК Таб

|;

|

|ВЫБРАТЬ

| ВТ.Номенклатура,

| ВТ.Количество,

| ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток

|ИЗ

| ВТ_Товары КАК ВТ

| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(, Склад = &Склад) КАК Остатки

| ПО ВТ.Номенклатура = Остатки.Номенклатура";

Результат = Запрос.Выполнить().Выгрузить();

Обратите внимание: первый пакет только материализует параметр во временную таблицу ВТ_Товары, а второй пакет выполняет основную выборку. Разделитель пакетов — точка с запятой на отдельной строке. Без ПОМЕСТИТЬ обратиться к параметру-таблице можно лишь один раз в одном пакете, что сильно ограничивает логику.

Порядок действий
  1. 1
    Сформируйте таблицу значений с типизированными колонками или выгрузите табличную часть методом Выгрузить()
  2. 2
    Установите таблицу как параметр: Запрос.УстановитьПараметр("Имя", Таблица)
  3. 3
    В первом пакете запроса выберите поля из &Имя и поместите их во временную таблицу через ПОМЕСТИТЬ
  4. 4
    Используйте временную таблицу в соединениях и отборах следующих пакетов
  5. 5
    Выполните запрос и проверьте результат через Выгрузить() или Выбрать()

Передача табличной части документа

Частый сценарий — передать в запрос табличную часть текущего документа, чтобы получить по ней данные из регистров или справочников. Табличную часть нельзя передать «как есть»: сначала её нужно выгрузить в таблицу значений методом Выгрузить(). При необходимости можно выгрузить только нужные колонки, перечислив их строкой.

ТаблицаТЧ = Объект.Товары.Выгрузить(, "Номенклатура, Количество, Цена");

Запрос.УстановитьПараметр("Товары", ТаблицаТЧ);

Выгрузка только нужных колонок уменьшает объём передаваемых данных и упрощает текст запроса. Если табличная часть содержит служебные поля, которые не нужны в запросе, их лучше не тащить во временную таблицу.

Менеджер временных таблиц и повторное использование

Если одна и та же таблица нужна в нескольких независимых запросах, создают объект МенеджерВременныхТаблиц и назначают его каждому запросу. Тогда временная таблица, созданная первым запросом, доступна второму без повторной передачи параметра.

МВТ = Новый МенеджерВременныхТаблиц;

Запрос1 = Новый Запрос;

Запрос1.МенеджерВременныхТаблиц = МВТ;

Запрос1.УстановитьПараметр("ТаблицаТоваров", ТаблицаТоваров);

Запрос1.Текст = "ВЫБРАТЬ Таб.Номенклатура ПОМЕСТИТЬ ВТ_Товары ИЗ &ТаблицаТоваров КАК Таб";

Запрос1.Выполнить();

Запрос2 = Новый Запрос;

Запрос2.МенеджерВременныхТаблиц = МВТ;

Запрос2.Текст = "ВЫБРАТЬ * ИЗ ВТ_Товары КАК ВТ";

После завершения работы менеджер временных таблиц желательно закрыть методом Закрыть() или дать объекту выйти из области видимости, чтобы временные таблицы были удалены с сервера СУБД. В длительных обработках с большими таблицами это заметно влияет на потребление ресурсов.

Если временная таблица нужна только внутри одного запроса, менеджер создавать не обязательно — платформа использует внутренний менеджер автоматически. Явный МенеджерВременныхТаблиц нужен именно для обмена временными таблицами между разными объектами «Запрос».
ПЗ
Практическое замечание

Отбор по таблице без соединения

Не всегда нужно соединять временную таблицу с основной выборкой. Если задача — просто отобрать записи по списку значений, достаточно условия В ИЕРАРХИИ или В с вложенным запросом к временной таблице:

ВЫБРАТЬ

| Остатки.Номенклатура,

| Остатки.КоличествоОстаток

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки

|ГДЕ

| Остатки.Номенклатура В (ВЫБРАТЬ ВТ.Номенклатура ИЗ ВТ_Товары КАК ВТ)

Левое соединение предпочтительнее, когда из временной таблицы нужны дополнительные поля (количество, цена, комментарий из строки). Условие В подходит, когда таблица-параметр играет роль чистого фильтра.

Сравнение вариантов

Левое соединение с ВТ

Подходит, когда из переданной таблицы нужны поля в результате. Сохраняет все строки временной таблицы, даже без совпадений в базе.

Условие В (вложенный запрос)

Подходит для чистого фильтра по списку значений. Не позволяет вытащить поля из таблицы-параметра в выборку.

Внутреннее соединение

Подходит, когда нужны только совпадающие строки обеих сторон. Строки параметра без данных в базе будут потеряны.

Индексирование и производительность

При соединении временной таблицы с большими таблицами базы данных имеет смысл проиндексировать поля связи. Для этого в первом пакете после списка полей добавляется конструкция ИНДЕКСИРОВАТЬ ПО:

ВЫБРАТЬ Таб.Номенклатура КАК Номенклатура

ПОМЕСТИТЬ ВТ_Товары

ИЗ &ТаблицаТоваров КАК Таб

ИНДЕКСИРОВАТЬ ПО Номенклатура

Индекс ускоряет соединение, когда во временной таблице сотни и тысячи строк. Для таблицы из двух-трёх строк индексирование эффекта не даст, но и не навредит. Также учитывайте, что передача очень большой таблицы (десятки тысяч строк) как параметра сама по себе занимает время — в таких случаях стоит пересмотреть архитектуру решения.

Типичные ошибки и ограничения

Большинство проблем при передаче таблицы в запрос связано с типами колонок и невнимательностью к структуре пакетного запроса. Ниже — ошибки, которые встречаются чаще всего.

Типичные ошибки
01
Колонка добавлена без типа — при выгрузке во временную таблицу возникает ошибка несовместимости типов или неожиданный тип поля
02
Обращение к &Параметру во втором пакете запроса — параметр-таблицу можно использовать только в одном пакете, дальше работайте через ПОМЕСТИТЬ
03
Передача табличной части без Выгрузить() — объект табличной части не является допустимым значением параметра
04
Пустая таблица-параметр с соединением ВНУТРЕННЕЕ — результат пустой, и это принимается за ошибку данных, хотя логика верна
05
Отсутствие ЕСТЬNULL при левом соединении — в полях остатков появляется NULL вместо нуля, что ломает последующие расчёты

Отдельно стоит упомянуть ограничение: поля временной таблицы наследуют типы из колонок таблицы значений. Если колонка имеет составной тип (например, несколько видов документов), соединение по такому полю может работать медленнее, а в некоторых СУБД — приводить к неоптимальным планам запроса. По возможности сужайте тип колонки до конкретного.

Контрольные точки

Как проверить результат

Выполнение запроса
Норма

Запрос выполняется без исключений, Выгрузить() возвращает таблицу с ожидаемым числом строк

Тревожный признак

Ошибка «Поле не найдено» или «Несовместимые типы» — проверьте имена и типы колонок параметра

Содержимое временной таблицы
Норма

Временная таблица содержит все строки переданного параметра

Тревожный признак

Строк меньше, чем в источнике — возможно, дубли свёрнуты или колонки выгружены не все

Соединение с данными базы
Норма

Совпадающие строки заполнены, несовпадающие дают NULL, обработанный через ЕСТЬNULL

Тревожный признак

Все поля соединения пустые — проверьте типы и значения полей связи

FAQ

Можно ли передать в запрос результат другого запроса?

Да. Выполните первый запрос, получите таблицу через Выгрузить() и передайте её параметром во второй запрос. Альтернатива — общий МенеджерВременныхТаблиц: тогда временная таблица первого запроса доступна второму напрямую, без выгрузки в память.

Почему возникает ошибка «Несовместимые типы» при передаче таблицы?

Чаще всего колонка таблицы значений создана без явного типа или содержит значения разных несовместимых типов. Добавьте колонку через Колонки.Добавить("Имя", Новый ОписаниеТипов("СправочникСсылка.Номенклатура")) и убедитесь, что все значения соответствуют указанному типу.

Можно ли использовать параметр-таблицу в двух пакетах одного запроса?

Нет. Обратиться к параметру с таблицей значений можно только один раз. Поэтому стандартный приём — в первом пакете поместить данные из параметра во временную таблицу через ПОМЕСТИТЬ, а дальше ссылаться уже на неё в любом количестве пакетов.

Что быстрее: передать таблицу в запрос или обойти строки в цикле?

Для выборки данных из базы запрос с временной таблицей практически всегда быстрее: он выполняется одним обращением к СУБД вместо обращения на каждую строку. Цикл оправдан только когда для каждой строки требуется сложная объектная логика, не выразимая запросом.

Как передать в запрос только часть колонок табличной части?

Используйте метод Выгрузить с перечислением колонок: Объект.Товары.Выгрузить(, "Номенклатура, Количество"). Первый параметр (отбор строк) оставьте пустым, если нужны все строки.

Нужно ли удалять временные таблицы после использования?

Желательно. Вызовите метод Закрыть() у менеджера временных таблиц после завершения работы — это освободит ресурсы сервера СУБД. Для запроса без явного менеджера временные таблицы удаляются автоматически после выполнения.

Итог

Что важно запомнить

Таблица передаётся в запрос через УстановитьПараметр, материализуется конструкцией ПОМЕСТИТЬ во временную таблицу и дальше используется в соединениях и отборах. Колонки должны быть типизированы, параметр-таблица доступен только в одном пакете, а для обмена временными таблицами между запросами применяется МенеджерВременныхТаблиц.