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

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

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

Как передать таблицу значений в запрос 1С через параметр: ВЫБРАТЬ ... ПОМЕСТИТЬ, временные таблицы, условия соединения, типичные ошибки и готовый пример кода.

Передача таблицы значений в запрос как параметра — стандартный приём в 1С, когда нужно отобрать или соединить данные информационной базы с произвольным набором строк, сформированным программно. Типичные сценарии: проверка списка номенклатуры на остатки, сопоставление загруженного из Excel прайса со справочником, пакетный поиск документов по массиву номеров.

Механизм одинаков во всех управляемых и обычных приложениях на платформе 8.3: таблица значений передаётся через Запрос.УстановитьПараметр(), во временную таблицу она попадает конструкцией ВЫБРАТЬ ... ПОМЕСТИТЬ ИЗ &Таблица КАК ..., а дальше используется в соединениях и условиях как обычный источник данных запроса.

Ниже разобран полный рабочий пример, ограничения платформы, способы ускорить запрос и типичные ошибки, из-за которых конструкция либо падает с ошибкой, либо возвращает пустой результат.

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

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

Второй сценарий — пакетная обработка. Вместо цикла «для каждой строки выполнить запрос» все строки передаются одним параметром, а обработка идёт на стороне СУБД. Это существенно быстрее: один запрос с соединением почти всегда выигрывает у сотен мелких запросов в цикле.

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

Базовый пример: передача таблицы в запрос

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

// 1. Создаём таблицу значений

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

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

ТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));

// 2. Заполняем данными

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

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

НоваяСтрока.Количество = 5;

// 3. Запрос с временной таблицей

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

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

"ВЫБРАТЬ

| Внешние.Артикул КАК Артикул,

| Внешние.Количество КАК Количество

|ПОМЕСТИТЬ ВТ_Внешние

|ИЗ

| &ТЗ КАК Внешние

|;

|

|ВЫБРАТЬ

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

| ВТ.Количество КАК Количество

|ИЗ

| ВТ_Внешние КАК ВТ

| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура

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

// 4. Передаём параметр и выполняем

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

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

Обратите внимание на синтаксис обращения к параметру: ИЗ &ТЗ КАК Внешние. Псевдоним обязателен — через него затем адресуются колонки. Имя параметра в УстановитьПараметр указывается без амперсанда.

Зачем типизировать колонки и как это сделать правильно

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

Правило простое: тип колонки в таблице значений должен точно совпадать с типом поля, с которым идёт сравнение. Строковый артикул в справочнике длиной 25 — значит, и колонка объявляется Строка(25). Ссылочное поле — значит, тип СправочникСсылка.Номенклатура, а не строка с представлением.

Если таблица получена выгрузкой результата другого запроса (Результат.Выгрузить()), типы колонок уже корректны — их не нужно переопределять. Это удобный способ получить «готовую» типизированную таблицу без ручного описания.

Условия и соединения: как использовать временную таблицу

После помещения во временную таблицу данные из параметра ведут себя как обычный источник. Два основных приёма — соединение и условие В.

Соединение с таблицами базы

Соединение нужно, когда требуется сопоставить строки и получить данные с обеих сторон. Используйте ВНУТРЕННЕЕ СОЕДИНЕНИЕ, если нужны только совпавшие строки, и ЛЕВОЕ СОЕДИНЕНИЕ от временной таблицы, если нужно увидеть, какие загруженные строки не нашлись в базе (признак — NULL в полях правой таблицы).

Отбор через условие В

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

Маршрут решения

Что выбрать для отбора

Отбор по одному полю, данные из внешнего набора не нужныПередайте массив параметром и используйте условие В (&Массив)
Нужно соединение по нескольким полям или данные из внешних строк (цена, количество)Передавайте таблицу значений и используйте временную таблицу с соединением
Нужно найти строки, отсутствующие в базеЛЕВОЕ СОЕДИНЕНИЕ от временной таблицы с проверкой поля базы на NULL

Производительность: индексы и объём данных

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

ВЫБРАТЬ

Внешние.Артикул КАК Артикул

ПОМЕСТИТЬ ВТ_Внешние

ИЗ

&ТЗ КАК Внешние

ИНДЕКСИРОВАТЬ ПО

Артикул

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

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

Типичные ошибки и их признаки

Большинство проблем с этим приёмом укладывается в короткий список. Если запрос падает или возвращает пустой результат, проверяйте в первую очередь типы колонок и совпадение имён.

Типичные ошибки
01
Колонки без типа: соединение строки произвольной длины со строкой фиксированной длины даёт ошибку или пустой результат из-за неявного приведения. Лечится явным ОписаниеТипов при создании колонки.
02
Несовпадение имён колонок и полей запроса: ошибка «Поле не найдено». Проверьте, что ТЗ.Колонки.Добавить("Артикул") и Внешние.Артикул — одно и то же имя.
03
Сравнение ссылки со строкой: в колонке лежит представление контрагента, а соединение идёт со ссылочным полем. Результат — пустая выборка без ошибки. Передавайте сами ссылки.
04
Конструкция ПОМЕСТИТЬ и выборка из параметра в одном запросе без разделителя пакетов «;» — синтаксическая ошибка. Каждый пакет отделяется точкой с запятой.
05
Повторное использование запроса без установки параметра: если объект Запрос используется в цикле, параметр нужно устанавливать на каждой итерации с новой таблицей.

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

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

Отладить такой запрос удобно в консоли запросов: она позволяет заполнить таблицу-параметр вручную или загрузить из табличного документа и посмотреть результат по шагам. Перед переносом запроса в код убедитесь, что временная таблица содержит ожидаемое число строк.

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

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

Число строк во временной таблице
Норма

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

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

Строк меньше — часть данных потеряна из-за типов или ошибок заполнения

Соединение со справочником
Норма

Все или ожидаемая часть строк нашли пару

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

Массовые NULL при левом соединении — несовпадение форматов ключевых полей

Время выполнения
Норма

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

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

Запрос «виснет» — нет индекса по полю соединения или передан слишком большой объём

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

Итог

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

Таблица значений передаётся в запрос через УстановитьПараметр и превращается во временную таблицу конструкцией ВЫБРАТЬ ... ПОМЕСТИТЬ ИЗ &Параметр. Обязательны типизированные колонки, совпадающие имена полей и корректные типы для соединений. Для больших таблиц добавляйте ИНДЕКСИРОВАТЬ ПО и делите данные на порции.

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

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

Нет. Параметр-таблицу нельзя использовать напрямую в условии ГДЕ или соединении — только как источник в конструкции ВЫБРАТЬ ... ИЗ &Параметр, результат которой помещается во временную таблицу. Дальнейшая работа идёт уже с ней.

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

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

Почему запрос с параметром-таблицей возвращает пустой результат без ошибки?

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

Работает ли этот приём в запросах динамических списков и СКД?

В СКД внешние наборы данных подключаются через коллекцию ВнешниеНаборыДанных при программном формировании отчёта — там таблица значений передаётся как объектный источник. В произвольном запросе динамического списка параметр-таблица использоваться не может, так как список должен опираться на таблицы базы.

Есть ли ограничение на количество строк в передаваемой таблице?

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

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

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