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