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

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

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

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

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

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

Ниже разобраны оба способа с готовыми примерами кода, особенности типизации колонок, типичные ошибки и способы проверить, что таблица реально попала в запрос и соединение отработало корректно.

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

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

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

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

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

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

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

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

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

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

Способ 1: помещение таблицы во временную таблицу запроса

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

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

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

"ВЫБРАТЬ

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

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

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

|ИЗ

| &ТЗ КАК ТЗ

|;

|

|ВЫБРАТЬ

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

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

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

|ИЗ

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

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

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

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

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

Обратите внимание: имя параметра в тексте запроса (&ТЗ) используется как псевдоним таблицы, а обращение к колонкам идёт через алиас (ТЗ.Номенклатура). Имена полей во временной таблице совпадают с именами колонок исходной таблицы значений.

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

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

Способ 2: фильтрация через оператор В

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

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

"ВЫБРАТЬ

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

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

|ИЗ

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

|ГДЕ

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

| (ВЫБРАТЬ ТЗ.Номенклатура ИЗ &ТЗ КАК ТЗ)";

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

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

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

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

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

Временная таблица (ПОМЕСТИТЬ из &ТЗ)

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

Оператор В с выборкой из &ТЗ

Подходит для фильтрации по одной колонке. Не позволяет получить остальные данные таблицы.

Массив в операторе В

Самый простой вариант для отбора по списку ссылок. Не подходит для передачи структурированных данных.

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

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

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

ЗапросИнициализации = Новый Запрос;

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

ЗапросИнициализации.Текст =

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

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

|ИЗ &ТЗ КАК ТЗ";

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

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

ЗапросОстатки = Новый Запрос;

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

ЗапросОстатки.Текст = "ВЫБРАТЬ ... ИЗ ВТ_Данные КАК ВТ ...";

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

Ограничения и производительность

Передача таблицы значений в запрос — не бесплатная операция. Платформа сериализует таблицу и загружает её в СУБД как временный набор данных. При таблицах в десятки тысяч строк это заметно по времени и по памяти. Практические рекомендации:

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

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

Типичные ошибки и их диагностика

Первая ошибка — передача таблицы без типизации колонок. Симптом: запрос падает с сообщением о невозможности определить тип поля или о несовместимости типов. Лечится явным заданием ОписаниеТипов при создании каждой колонки.

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

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

Четвёртая ошибка — попытка использовать параметр с таблицей значений в операторе сравнения на равенство (ГДЕ Поле = &ТЗ). Таблица — не скалярное значение, такое сравнение недопустимо. Используйте В с подзапросом или соединение.

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

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

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

ЗапросПроверки = Новый Запрос;

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

ЗапросПроверки.Текст = "ВЫБРАТЬ * ИЗ ВТ_Данные";

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

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

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

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

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

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

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

Строк меньше или ноль — проверяйте заполнение и типизацию колонок

Типы полей временной таблицы
Норма

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

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

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

Результат соединения
Норма

К каждой строке присоединены данные из базы, где они существуют

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

Все присоединённые поля NULL — несовпадение значений или типов ключей

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

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

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

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

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

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

Чаще всего причина в типизации: в консоли таблица уже подготовлена, а в коде колонки создаются без ОписаниеТипов или заполняются значениями другого типа. Сравните структуру таблицы в отладчике с той, что используется в консоли.

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

Создайте новую таблицу значений с нужными колонками и скопируйте в неё данные, либо используйте метод Скопировать() с указанием списка колонок: ТЗ.Скопировать(, "Номенклатура,Количество"). В запросе из параметра выбираются только существующие колонки.

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

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

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

Да, механизм параметров-таблиц работает и для запросов к внешним источникам данных, если соответствующий СУБД-драйвер поддерживает табличные параметры. Практическую применимость стоит проверять на конкретной связке СУБД и платформы.

Итог

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

Таблица значений передаётся через УстановитьПараметр и используется в запросе как источник ИЗ &Параметр. Для соединений помещайте её во временную таблицу, для простого отбора достаточно оператора В. Всегда типизируйте колонки, индексируйте поля соединения и контролируйте объём передаваемых данных.