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

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

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

Как передать таблицу значений в запрос 1С 8 через УстановитьПараметр, объявить временную таблицу через ВТ, отфильтровать данные и избежать типичных ошибок с типами колонок.

Передача таблицы значений в запрос — один из базовых приёмов разработки на платформе 1С:Предприятие 8. Он нужен всякий раз, когда данные уже собраны в памяти (результат обмена, выборка из другого запроса, загруженный файл), а дальше их требуется сопоставить с данными информационной базы: подобрать ссылки по кодам, отфильтровать список товаров, свернуть остатки по заранее известному набору номенклатуры.

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

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

Когда таблицу значений передают в запрос

Типовой сценарий — фильтрация по заранее известному набору значений. Например, из файла Excel загружены 500 артикулов, и нужно получить по ним цены и остатки. Формировать 500 условий ИЛИ в тексте запроса нельзя, а временная таблица решает задачу одним соединением.

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

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

Минимальный рабочий пример

Базовый код состоит из трёх частей: создания и заполнения таблицы значений, передачи её параметром и объявления временной таблицы в тексте запроса.

ТЗ = Новый ТаблицаЗначений;

ТЗ.Колонки.Добавить("Артикул", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(50)));

НоваяСтрока = ТЗ.Добавить();

НоваяСтрока.Артикул = "ТОВ-001";

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

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

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

"ВЫБРАТЬ

| ТЗ.Артикул КАК Артикул

|ПОМЕСТИТЬ ВТ_Артикулы

|ИЗ

| &ТЗ КАК ТЗ

|;

|ВЫБРАТЬ

| Номенклатура.Ссылка КАК Ссылка,

| Номенклатура.Артикул КАК Артикул

|ИЗ

| Справочник.Номенклатура КАК Номенклатура

| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Артикулы КАК ВТ

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

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

Обратите внимание на три момента. Во-первых, параметр называется &ТЗ в первом запросе пакета — именно там таблица «материализуется» во временную таблицу ВТ_Артикулы. Во-вторых, во втором запросе пакета обращение идёт уже к временной таблице, а не к параметру. В-третьих, между запросами пакета ставится точка с запятой.

Соединение и фильтрация по временной таблице

После помещения данных во временную таблицу доступны все стандартные операции языка запросов. Чаще всего используется внутреннее соединение — оно вернёт только те записи базы, которые есть в переданном наборе:

ВЫБРАТЬ

ВТ.Артикул КАК Артикул,

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

ИЗ

ВТ_Артикулы КАК ВТ

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

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

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

Допустимо и использование временной таблицы в условии ГДЕ ... В (ВЫБРАТЬ ...), но соединение обычно читается лучше и позволяет вытащить в результат поля из переданной таблицы — например, исходный номер строки файла для последующего сопоставления.

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

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

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

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

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

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

Запрос.Текст = "ВЫБРАТЬ ТЗ.Номенклатура КАК Номенклатура

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

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

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

// последующие запросы с тем же МенеджерВТ видят ВТ_Товары

Все запросы, у которых установлен один и тот же менеджер временных таблиц, видят таблицы друг друга. Это стандартный приём для сложных отчётов: сначала строится набор временных таблиц, затем финальный запрос собирает результат.

Когда временная таблица больше не нужна, её стоит явно удалить командой УНИЧТОЖИТЬ ВТ_Товары — это освобождает память сервера, что критично при обработке крупных объёмов в цикле.

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

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

Самая частая проблема — несовпадение типов. Колонка таблицы значений имеет тип Строка(100), а поле в базе — Строка(50): соединение сработает, но при неявном приведении возможны потери данных или отказ от использования индекса. Выравнивайте длины и типы заранее.

Вторая ошибка — попытка обратиться к параметру &ТЗ во втором запросе пакета. Параметр-таблица доступен только один раз, в месте помещения во временную таблицу. Дальше работайте только с ВТ.

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

Отдельное ограничение: поля таблицы значений нельзя использовать в запросе как источник для обхода иерархии или в некоторых специфических конструкциях виртуальных таблиц. Если запрос ведёт себя странно, проверьте, не упирается ли он в ограничение языка запросов, а не в данные.

Типичные ошибки
01
Передача таблицы без описания типов колонок — непредсказуемые типы полей ВТ и ошибки соединения
02
Обращение к &ТЗ во втором запросе пакета — ошибка исполнения, параметр доступен только при ПОМЕСТИТЬ
03
Передача пустой таблицы — ошибка запроса, нужна проверка Количество() > 0
04
Соединение по строковым полям вместо ссылок — потеря индексов и резкое падение скорости
05
Отсутствие ИНДЕКСИРОВАТЬ ПО для крупных таблиц — медленные соединения

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

После выполнения запроса проверьте, что временная таблица заполнилась ожидаемо. Быстрый способ — выполнить отдельный запрос ВЫБРАТЬ * ИЗ ВТ_Товары с тем же менеджером временных таблиц и посмотреть состав и количество строк в отладчике.

Контрольные точки: число строк во временной таблице должно совпадать с числом строк исходной таблицы значений; типы полей — соответствовать описанию колонок; итоговая выборка не должна содержать NULL там, где соединение объявлено внутренним.

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

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

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

Число строк во ВТ
Норма

Совпадает с ТЗ.Количество()

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

Строк меньше или ВТ пуста при заполненной таблице

Типы полей ВТ
Норма

Совпадают с типами колонок таблицы значений

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

Составные или неожиданные типы

NULL в результате
Норма

NULL только при левом соединении

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

NULL при внутреннем соединении — ошибка логики

Скорость выполнения
Норма

Запрос выполняется за секунды

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

Минуты на больших таблицах — проверьте индексацию

Частые вопросы

Итог

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

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

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

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

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

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

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

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

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

Если нужен один столбец, проще использовать список значений в условии В: Запрос.УстановитьПараметр("Список", СписокЗначений) и условие ГДЕ Поле В (&Список). Временная таблица оправдана, когда полей два и больше.

Нужно ли уничтожать временные таблицы вручную?

Для разового запроса — необязательно: таблицы исчезнут вместе с менеджером временных таблиц. Но в циклах и длительных обработках явный УНИЧТОЖИТЬ освобождает память сервера и предотвращает её разрастание.

Работает ли передача таблицы значений в СКД?

Да, но по-другому: в СКД таблица значений подключается как внешний набор данных через объект «ТаблицаЗначений» в схеме компоновки и передаётся в процессор компоновки, а не как параметр запроса. Механизм с &ТЗ и ПОМЕСТИТЬ относится к обычным запросам.