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