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

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

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

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

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

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

Материал применим к управляемым и обычным приложениям на платформе 8.3, синтаксис одинаков для тонкого, толстого и веб-клиента. Отдельно рассмотрены ограничения по объёму данных и вопросы производительности, потому что именно здесь чаще всего возникают проблемы на больших таблицах.

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

Таблица значений — удобный универсальный контейнер, но у неё нет встроенных средств группировки с агрегатными функциями, соединений и сложной фильтрации. Метод Свернуть() умеет только суммировать числовые колонки, а поиск строк через НайтиСтроки() на больших объёмах работает медленно. Запрос решает эти задачи декларативно и быстро, потому что обработка выполняется на стороне СУБД.

Типовые сценарии, где передача таблицы в запрос оправдана: сверка загруженных из Excel данных с остатками или ценами в базе; группировка строк с несколькими итогами; проверка, какие элементы из таблицы уже существуют в справочнике; соединение расчётных данных с регистрами для формирования отчёта. Во всех этих случаях альтернатива — обход таблицы в цикле с запросом внутри — работает на порядки медленнее.

Базовый способ: параметр запроса и ПОМЕСТИТЬ

Самый простой вариант — передать таблицу значений параметром и сразу поместить её во временную таблицу. Порядок действий: создать объект Запрос, установить параметр с таблицей, написать текст запроса с обращением к параметру как к источнику данных.

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

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

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

"ВЫБРАТЬ

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

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

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

|ИЗ

| &ТЗ КАК ТЗ

|;

|ВЫБРАТЬ

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

| СУММА(ВТ.Количество) КАК Количество

|ИЗ

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

|СГРУППИРОВАТЬ ПО

| ВТ.Номенклатура";

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

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

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

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

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

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

"ВЫБРАТЬ

| ТЗ.Артикул КАК Артикул,

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

|ПОМЕСТИТЬ ВТ_Загрузка

|ИЗ

| &ТЗ КАК ТЗ

|;

|ВЫБРАТЬ

| ВТ.Артикул КАК Артикул,

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

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

|ИЗ

| ВТ_Загрузка КАК ВТ

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

| ПО ВТ.Артикул = Ном.Артикул

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

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

Используйте ЛЕВОЕ СОЕДИНЕНИЕ, если нужно видеть строки, для которых соответствие в базе не найдено, — в полях соединяемой таблицы будет NULL. Это удобный способ сразу получить список «не найденных» позиций: добавьте условие ГДЕ Ном.Ссылка ЕСТЬ NULL. Функция ЕСТЬNULL() подставляет значение по умолчанию вместо NULL в числовых полях.

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

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

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

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

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

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

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

"ВЫБРАТЬ ТЗ.* ПОМЕСТИТЬ ВТ_Данные ИЗ &ТЗ КАК ТЗ";

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

// Далее любое количество запросов с тем же менеджером

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

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

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

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

Временные таблицы живут, пока существует менеджер. Когда работа завершена, менеджер стоит явно закрыть методом Закрыть() — это освобождает ресурсы сервера СУБД. Также помните: временная таблица видна только запросам с тем же менеджером, попытка обратиться к ней из запроса без менеджера даст ошибку «Таблица не найдена».

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

Параметр + ПОМЕСТИТЬ в одном запросе

Подходит для разовой обработки. Просто и наглядно, но таблицу придётся передавать заново в каждый запрос.

МенеджерВременныхТаблиц

Оптимален при нескольких запросах к одним данным. Требует контроля времени жизни менеджера и явного закрытия.

Обход таблицы в цикле

Без запроса вообще. Приемлем только для маленьких таблиц и простой логики; на объёмах от тысяч строк заметно проигрывает по скорости.

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

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

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

ТаблицаЗначений.Колонки.Добавить("Артикул",

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

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

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

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

Типичные ошибки
01
Опечатка в имени колонки: запрос падает с ошибкой «Поле не найдено», потому что имена полей должны точно совпадать с именами колонок таблицы значений
02
Передача таблицы без явных типов колонок: составные или неопределённые типы ломают соединения и сравнения в запросе
03
Обращение к временной таблице из запроса без установленного МенеджераВременныхТаблиц — ошибка «Таблица не найдена: ВТ_Данные»
04
Использование ВЫБРАТЬ * из параметра-таблицы с последующим соединением: лишние поля увеличивают объём временной таблицы, выбирайте только нужные колонки
05
Передача таблицы с незаполненными (NULL-подобными) значениями без обработки ЕСТЬNULL — итоговые суммы и сравнения дают неожиданный результат

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

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

Для отладки временных таблиц удобно выгружать их содержимое в отдельный запрос с тем же менеджером и просматривать в консоли запросов или через отладчик. В конфигураторе точка останова на строке после Выполнить() позволяет посмотреть результат выборки в табличном документе через Вывести() внешней обработки или просто оценить выражение.

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

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

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

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

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

Строк меньше или больше — проверяйте фильтры и соединения

Типы полей результата
Норма

Числовые поля суммируются, ссылки соединяются с таблицами базы

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

Соединение по полю не находит совпадений при заведомо существующих данных

Итоговые суммы после группировки
Норма

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

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

Расхождения — ищите NULL в числовых колонках или дубли строк

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

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

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

"ВЫБРАТЬ

| ТЗ.Артикул КАК Артикул,

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

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

|ИЗ

| &ТЗ КАК ТЗ

|

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

| Артикул";

Часто задаваемые вопросы

Можно ли передать таблицу значений в запрос без ПОМЕСТИТЬ?

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

Почему запрос выдаёт ошибку «Поле не найдено», хотя колонка в таблице есть?

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

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

Два способа: либо перечислить нужные поля в запросе (ВЫБРАТЬ ТЗ.Поле1, ТЗ.Поле2 ИЗ &ТЗ) — лишние колонки просто не попадут во временную таблицу; либо заранее создать усечённую копию через ТаблицаЗначений.Скопировать(, "Поле1,Поле2") и передать её.

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

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

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

В СКД таблицу значений подключают как внешний набор данных через объект «ТаблицаЗначений» в схеме компоновки — там не нужен параметр запроса. Механизм с УстановитьПараметр применяется при программной работе с объектом Запрос, когда нужна гибкая обработка вне отчётов.

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

Напрямую обновить временную таблицу запросом нельзя — язык запросов 1С не поддерживает UPDATE по временным таблицам. Создайте новую временную таблицу на основе существующей с нужными преобразованиями, либо уничтожьте старую (УНИЧТОЖИТЬ ВТ_Данные) и поместите данные заново.

Итог

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

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