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