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

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

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

Как передать таблицу значений в запрос 1С как параметр: установка параметра, временные таблицы, соединение с ТЗ, типичные ошибки и примеры кода.

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

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

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

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

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

Пример подготовки таблицы со списком номенклатуры и количеством:

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

ТЗ.Колонки.Добавить("Номенклатура",

Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));

ТЗ.Колонки.Добавить("Количество",

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

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

НоваяСтрока.Номенклатура = СсылкаНаТовар;

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

Обратите внимание на типы ссылочных колонок. Если в колонке лежит ссылка на справочник, а тип объявлен как строка, соединение с таблицей справочника в запросе не сработает корректно. Тип колонки ТЗ должен совпадать с типом поля, с которым она будет соединяться.

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

Установка параметра и текст запроса

Параметр устанавливается методом УстановитьПараметр() до выполнения запроса. В тексте запроса параметр-ТЗ используется только в предложении ПОМЕСТИТЬ — напрямую в ГДЕ или соединении сослаться на &ТЗ нельзя.

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

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

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

"ВЫБРАТЬ

| ТЗ.Номенклатура КАК Номенклатура,

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

|ПОМЕСТИТЬ ВТ_Данные

|ИЗ

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

|;

|

|ВЫБРАТЬ

| ВТ.Номенклатура КАК Номенклатура,

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

| ЕСТЬNULL(Цены.Цена, 0) КАК Цена

|ИЗ

| ВТ_Данные КАК ВТ

| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних() КАК Цены

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

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

Имена колонок во временной таблице берутся из имён колонок таблицы значений. Синонимы (КАК) в первом выборе задавать не обязательно, но рекомендуется — так текст запроса читается проще и устойчивее к переименованиям.

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

Если временная таблица нужна в нескольких последовательных запросах, используйте МенеджерВременныхТаблиц. Без него временные таблицы уничтожаются после выполнения пакета, и каждый запрос должен заново помещать ТЗ.

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

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

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

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

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

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

|ПОМЕСТИТЬ ВТ_Номенклатура

|ИЗ &ВнешняяТЗ КАК ТЗ";

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

// Дальше ВТ_Номенклатура доступна в других запросах

// с тем же менеджером временных таблиц

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

Порядок действий
  1. 1
    Создайте таблицу значений и явно опишите типы колонок через ОписаниеТипов
  2. 2
    Заполните ТЗ данными
  3. 3
    Создайте объект Запрос и при необходимости МенеджерВременныхТаблиц
  4. 4
    Вызовите Запрос.УстановитьПараметр("Имя", ТЗ)
  5. 5
    В тексте запроса поместите параметр во временную таблицу: ВЫБРАТЬ ... ПОМЕСТИТЬ ВТ ИЗ &Имя
  6. 6
    Напишите основной запрос с соединением к временной таблице
  7. 7
    Выполните запрос и проверьте результат выборкой или выгрузкой

Варианты соединения и фильтрации по ТЗ

Левое соединение — сохранить все строки ТЗ

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

Внутреннее соединение — только совпадения

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

Фильтрация через В (ВЫБРАТЬ ...)

Если соединение не нужно, а требуется только отфильтровать таблицу базы по значениям из ТЗ, используйте условие с подзапросом:

ВЫБРАТЬ

| Док.Ссылка КАК Ссылка

|ИЗ

| Документ.РеализацияТоваровУслуг КАК Док

|ГДЕ

| Док.Контрагент В (ВЫБРАТЬ ВТ.Контрагент ИЗ ВТ_Контрагенты КАК ВТ)

Такой вариант читается проще соединения и не размножает строки, если в ТЗ встречаются дубли значений.

Сравнение вариантов

Левое соединение

Сохраняет все строки ТЗ, не найденные получают NULL. Подходит для загрузок и сверок. Требует ЕСТЬNULL для числовых полей.

Внутреннее соединение

Только совпавшие строки. Подходит для проверки существования. Дубли в ТЗ умножат строки результата.

Условие В (ВЫБРАТЬ ...)

Фильтрация без соединения, дубли в ТЗ не влияют на результат. Не позволяет вытащить дополнительные колонки из ТЗ.

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

Самая частая ошибка — попытка использовать параметр-ТЗ напрямую в условии ГДЕ Поле В (&ТЗ). Для списка значений это работает (массив или список передаётся как параметр без временной таблицы), а для таблицы значений — нет: платформа выдаст ошибку о несоответствии типов. ТЗ требует именно помещения во временную таблицу.

Вторая группа ошибок связана с типами и именами колонок. Если колонка ТЗ называется так же, как поле таблицы базы, а псевдонимы не расставлены, запрос может вернуть неоднозначность. Если тип колонки не совпадает с типом поля соединения, соединение молча не найдёт совпадений или запрос упадёт с ошибкой — зависит от СУБД и режима совместимости.

Производительность — отдельная тема. Таблица значений при передаче в запрос сериализуется и материализуется на стороне СУБД. Для таблиц в десятки тысяч строк это заметная нагрузка. Если ТЗ большая и используется только для фильтрации по одному полю, часто эффективнее передать массив значений и использовать В (&Массив) без временной таблицы.

Типичные ошибки
01
Использование &ТЗ напрямую в ГДЕ без ПОМЕСТИТЬ — ошибка выполнения запроса
02
Колонки без явного типа — соединение по ссылке не находит совпадений или запрос падает
03
Забытый ЕСТЬNULL при левом соединении — в числовых полях результата появляется NULL вместо 0
04
Дубли строк в ТЗ при внутреннем соединении — задвоение итоговых сумм
05
Передача огромной ТЗ ради фильтрации по одному полю — лучше передать массив значений
06
Обращение к временной таблице из другого запроса без общего МенеджераВременныхТаблиц — таблица не найдена

Альтернативы передаче ТЗ

Если нужна только фильтрация по одному полю, передайте массив или список значений обычным параметром и используйте ГДЕ Поле В (&Список). Это проще по коду и обычно не уступает по скорости на умеренных объёмах.

Если данные уже находятся в базе (например, результат другого запроса), не выгружайте их в ТЗ и не передавайте обратно — соединяйтесь подзапросом или оформляйте первый запрос как временную таблицу в общем менеджере. Каждый лишний обход «база → клиент/серверный код → база» — потерянное время.

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

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

Как выбрать действие

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

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

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

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

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

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

Количество строк результата при левом соединении
Норма

Не меньше числа строк исходной ТЗ

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

Меньше — ТЗ не попала в запрос целиком; сильно больше — дубли в соединяемой таблице

Числовые поля из соединённой таблицы
Норма

Числа или 0 там, где соответствия нет

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

NULL — не применён ЕСТЬNULL

Содержимое временной таблицы
Норма

Все строки и колонки ТЗ на месте, типы корректны

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

Пусто или типы ссылок определены как строки

Итог

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

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

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

Можно ли использовать параметр-ТЗ в условии ГДЕ напрямую?

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

Почему соединение с временной таблицей не находит совпадений?

Чаще всего не совпадают типы: колонка ТЗ объявлена без типа или как строка, а соединяется со ссылочным полем. Проверьте описание типов колонок при создании ТЗ. Вторая причина — лишние пробелы или разный регистр в строковых ключах при загрузке из внешних файлов.

Нужен ли индекс для временной таблицы из ТЗ?

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

Как передать ТЗ в запрос динамического списка?

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

Что быстрее: ТЗ с временной таблицей или массив в параметре?

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

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

Нет. Вложенные таблицы значений в параметр запроса не передаются — при помещении во временную таблицу такая колонка вызовет ошибку. Структуру «шапка + строки» передают двумя связанными ТЗ или одной плоской таблицей с колонкой-ключом.