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