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