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