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

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

Таблица значений в запрос 1С как параметр: полная инструкция

Как передать таблицу значений в запрос 1С через параметр: создание временной таблицы, соединение, фильтрация, типичные ошибки и готовые примеры кода.

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

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

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

Зачем передавать таблицу значений в запрос

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

Второй сценарий — сложная фильтрация по нескольким колонкам одновременно. Условие вида Номенклатура В (&Список) работает только с одномерным массивом. Если отбирать нужно по паре «Номенклатура + Характеристика» или «Контрагент + Договор», единственный корректный способ — временная таблица с соединением по обоим полям.

Третий сценарий — передача в запрос вычисленных в коде данных: курсов, коэффициентов, произвольных соответствий «значение → комментарий», которых нет в базе, но которые нужны в результате запроса.

Базовый пример: от параметра к временной таблице

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

bsl
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));

НоваяСтрока = ТЗ.Добавить();
НоваяСтрока.Номенклатура = СсылкаНаТовар;
НоваяСтрока.Количество = 10;

Запрос = Новый Запрос;
Запрос.УстановитьПараметр("ТЗ", ТЗ);
Запрос.Текст =
"ВЫБРАТЬ
|	Т.Номенклатура КАК Номенклатура,
|	Т.Количество КАК Количество
|ПОМЕСТИТЬ ВТ_Данные
|ИЗ
|	&ТЗ КАК Т
|;
|ВЫБРАТЬ
|	ВТ.Номенклатура,
|	ВТ.Количество,
|	Остатки.КоличествоОстаток
|ИЗ
|	ВТ_Данные КАК ВТ
|	ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
|	ПО ВТ.Номенклатура = Остатки.Номенклатура";
Результат = Запрос.Выполнить().Выгрузить();

Ключевой фрагмент — конструкция ИЗ &ТЗ КАК Т внутри первого подзапроса. Именно здесь параметр-таблица материализуется во временную таблицу ВТ_Данные. Все колонки таблицы значений должны быть перечислены в списке выборки явно — оператор * для параметра-таблицы не работает.

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

Требования к типам колонок

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

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

Для строковых колонок задавайте длину через КвалификаторыСтроки. Строка неограниченной длины во временной таблице на некоторых СУБД превращается в поле типа TEXT/MEMO, по которому нельзя построить индекс и нельзя соединяться без преобразования. Для чисел указывайте разрядность и точность, достаточные для данных, но не завышенные.

Фильтрация по нескольким полям через соединение

Классическая задача: есть список пар «Номенклатура + Характеристика», нужно получить остатки именно по этим парам. Условие В здесь не поможет — оно не умеет сопоставлять кортежи. Решение — внутреннее соединение по всем ключевым полям:

bsl
Запрос.Текст =
"ВЫБРАТЬ
|	Т.Номенклатура КАК Номенклатура,
|	Т.Характеристика КАК Характеристика
|ПОМЕСТИТЬ ВТ_Отбор
|ИЗ
|	&ТЗ КАК Т
|;
|ВЫБРАТЬ
|	ВТ.Номенклатура,
|	ВТ.Характеристика,
|	Остатки.КоличествоОстаток
|ИЗ
|	ВТ_Отбор КАК ВТ
|	ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
|	ПО ВТ.Номенклатура = Остатки.Номенклатура
|	И ВТ.Характеристика = Остатки.Характеристика";

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

Способы отбора по списку значений

Условие В (&Массив)

Подходит для отбора по одному полю. Просто и быстро, но не работает с парами значений и не передаёт дополнительные данные.

Временная таблица из ТЗ

Универсальный вариант: соединение по любому числу полей, передача вычисленных колонок, повторное использование в пакете запросов. Требует типизации колонок.

Перебор в цикле с запросами

Допустим только для единичных строк. На десятках итераций создаёт лишнюю нагрузку на СУБД и замедляет обработку в разы.

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

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

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

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

Запрос2 = Новый Запрос;
Запрос2.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос2.Текст = "ВЫБРАТЬ * ИЗ ВТ_Данные";
Результат = Запрос2.Выполнить();

Без менеджера временных таблиц каждая временная таблица живёт только внутри одного пакета запроса и удаляется сразу после выполнения. Если второй запрос обратится к несуществующей таблице, платформа выдаст ошибку «Таблица не найдена».

Ограничения и производительность

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

Дубли строк в таблице значений переносятся во временную таблицу как есть. Если вы соединяете такую таблицу с регистром, каждая строка-дубль умножит результат. При необходимости устраняйте дубликаты на этапе помещения: ВЫБРАТЬ РАЗЛИЧНЫЕ ... ПОМЕСТИТЬ или группировкой.

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

Типичные ошибки
01
Обращение к параметру-таблице в соединении без ПОМЕСТИТЬ — запрос падает с ошибкой, так как параметр не является таблицей базы данных
02
Нетипизированные колонки — соединение молча не находит совпадений или запрос выполняется в разы медленнее
03
Строковые колонки без ограничения длины — на СУБД создаётся поле, по которому невозможно соединение с обычными строковыми полями
04
Дубли строк в ТЗ без РАЗЛИЧНЫЕ — результат соединения задваивается, итоги завышаются
05
Использование звёздочки ВЫБРАТЬ * ИЗ &ТЗ — синтаксическая ошибка, колонки нужно перечислять явно
06
Повторная передача одной и той же ТЗ в несколько запросов вместо общего менеджера временных таблиц — лишняя выгрузка данных на сервер

Проверка результата

После внедрения механизма проверьте три вещи. Во-первых, количество строк во временной таблице должно совпадать с количеством строк таблицы значений (или быть меньше, если применялись РАЗЛИЧНЫЕ/группировка) — выполните отладочный запрос ВЫБРАТЬ КОЛИЧИЕСТВО(*) ИЗ ВТ_Данные. Во-вторых, убедитесь, что соединение находит ожидаемые совпадения: возьмите одну заведомо существующую в базе строку и проверьте, что она попала в результат. В-третьих, сравните итоги с эталонным отчётом конфигурации, если запрос дублирует штатную логику.

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

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

Число строк во временной таблице
Норма

Совпадает с числом строк таблицы значений (или с числом уникальных строк при РАЗЛИЧНЫЕ)

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

Строк меньше без явной причины — возможна потеря данных при типизации

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

Контрольная строка с заведомо существующей ссылкой найдена

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

Соединение возвращает пустой результат — проверяйте типы колонок

Итоговые суммы
Норма

Совпадают с штатным отчётом или ручным расчётом

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

Суммы завышены кратно — вероятны дубли строк в исходной ТЗ

FAQ

Можно ли использовать таблицу значений в запросе без ПОМЕСТИТЬ?

Нет. Параметр-таблица доступен только как источник в конструкции ВЫБРАТЬ ... ИЗ &Параметр, и результат этой выборки должен быть помещён во временную таблицу. Использовать параметр напрямую в соединении или условии нельзя.

Чем отличается передача массива от передачи таблицы значений?

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

Почему запрос с временной таблицей работает медленно?

Чаще всего причины три: неиндексированная временная таблица (добавьте ИНДЕКСИРОВАТЬ ПО после ПОМЕСТИТЬ), составной или несовпадающий тип колонки соединения, очень большой объём передаваемой таблицы. Начните проверку с типов колонок — это самая частая причина.

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

Да, через Выгрузить() результата вы получите таблицу значений, которую можно установить параметром следующего запроса. Но эффективнее использовать общий менеджер временных таблиц и объединить оба запроса в один пакет — данные не покинут сервер СУБД.

Что делать, если таблица значений содержит миллион строк?

Такой объём не стоит передавать параметром целиком — выгрузка займёт много времени и памяти. Разбейте обработку на порции по несколько тысяч строк или пересмотрите логику: возможно, данные уже есть в базе и их можно получить запросом без внешней таблицы.

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

Если менеджер временных таблиц больше не используется, таблицы удалятся автоматически при его уничтожении. В длительных обработках с одним менеджером на много запросов большие таблицы лучше удалять явно командой УНИЧТОЖИТЬ, чтобы не держать ресурсы СУБД.

Итог

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

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