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

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

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

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

В терминологии 1С понятие «виртуальная таблица» используется в двух смыслах, и их важно различать. Первый смысл — встроенные виртуальные таблицы регистров: Остатки, Обороты, СрезПоследних, СрезПервых, Границы и другие. Они не хранятся в базе физически, а вычисляются платформой из таблиц движений в момент выполнения запроса. Второй смысл, который часто подразумевают разработчики, — временная таблица, созданная внутри пакетного запроса конструкцией ПОМЕСТИТЬ.

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

Материал ориентирован на разработчиков и внедренцев, работающих в конфигураторе или консоли запросов. Примеры приведены на встроенном языке запросов 1С и подходят для управляемых приложений на платформе 8.3.

Что такое виртуальная таблица в 1С и когда она нужна

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

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

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

Обращение к виртуальным таблицам регистров

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

ВЫБРАТЬ

Остатки.Номенклатура,

Остатки.Склад,

Остатки.КоличествоОстаток

ИЗ

РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад) КАК Остатки

Первый параметр — период, на который рассчитываются остатки. Если передать пустую дату или опустить параметр, будут взяты остатки на текущий момент. Второй параметр — условие отбора по измерениям и реквизитам; его синтаксис похож на условие ГДЕ, но выполняется на уровне выборки итогов, что быстрее.

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

Создание временной таблицы через ПОМЕСТИТЬ

Конструкция ПОМЕСТИТЬ ИмяТаблицы записывает результат выборки во временную таблицу, доступную в последующих запросах пакета. Запросы в пакете разделяются точкой с запятой. Типовой пример — выбор номенклатуры по условию во временную таблицу и последующее соединение с остатками:

ВЫБРАТЬ

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

Товары.Наименование

ПОМЕСТИТЬ ВТ_Товары

ИЗ

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

ГДЕ

НЕ Товары.ПометкаУдаления

И Товары.ЭтоГруппа = ЛОЖЬ

;

ВЫБРАТЬ

ВТ_Товары.Номенклатура,

Остатки.КоличествоОстаток

ИЗ

ВТ_Товары КАК ВТ_Товары

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

ПО ВТ_Товары.Номенклатура = Остатки.Номенклатура

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

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

Порядок создания временной таблицы
  1. 1
    Сформулируйте выборку: какие поля и из какого источника нужны дальше
  2. 2
    Добавьте ПОМЕСТИТЬ ВТ_ИмяТаблицы после секции выбора полей
  3. 3
    Отделите следующий запрос точкой с запятой и обратитесь к ВТ_ИмяТаблицы в секции ИЗ
  4. 4
    При необходимости освободите память конструкцией УНИЧТОЖИТЬ ВТ_ИмяТаблицы
  5. 5
    Выполните пакет в консоли запросов и проверьте содержимое временной таблицы отдельным запросом ВЫБРАТЬ * ИЗ ВТ_ИмяТаблицы

Передача таблицы значений как виртуальной таблицы

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

ВЫБРАТЬ

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

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

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

ИЗ

&ТаблицаДанных КАК ТЗ

;

ВЫБРАТЬ

ВТ_Данные.Номенклатура,

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

ИЗ

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

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

ПО ВТ_Данные.Номенклатура = Цены.Номенклатура

В коде перед выполнением параметр заполняется так: Запрос.УстановитьПараметр("ТаблицаДанных", ТаблицаЗначений);. У таблицы значений должны быть явно описаны колонки с типами — иначе платформа не сможет построить временную таблицу корректно, особенно если колонка окажется пустой.

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

bsl
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.УстановитьПараметр("ТаблицаДанных", ТаблицаЗначений);
Запрос.Текст = "ВЫБРАТЬ Т.Номенклатура ПОМЕСТИТЬ ВТ_Данные ИЗ &ТаблицаДанных КАК Т";
Запрос.Выполнить();

Оптимизация: индексы и уничтожение временных таблиц

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

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

Ещё одно правило производительности: помещайте во временную таблицу только те поля, которые реально используются дальше. Выборка «звёздочкой» или с лишними полями увеличивает объём данных в памяти и замедляет соединения.

Три способа получить виртуальную таблицу

Встроенная виртуальная таблица регистра

Подходит для остатков, оборотов и срезов. Быстро, но набор полей и логика фиксированы платформой.

ПОМЕСТИТЬ из таблиц базы

Гибкая фильтрация и любые поля. Требует аккуратности с именами и объёмом данных.

ПОМЕСТИТЬ из параметра-таблицы

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

Типичные ошибки и как их избежать

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

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

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

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

Проверка результата и ограничения

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

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

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

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

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

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

Количество строк совпадает с ожидаемым отбором, поля имеют нужные типы

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

Строк больше или меньше ожидаемого, поля имеют неопределённый тип

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

Итоговая выборка не содержит дублей по ключевому полю

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

Строки размножились — в условии связи не хватает полей

Скорость выполнения
Норма

Запрос с отбором в параметрах виртуальной таблицы выполняется быстро

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

Запрос «виснет» — отбор вынесен в ГДЕ или не ограничен период

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

Чем виртуальная таблица отличается от временной таблицы?

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

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

Да, если обоим запросам назначен один и тот же объект МенеджерВременныхТаблиц. Создайте менеджер в коде, присвойте его свойству МенеджерВременныхТаблиц каждого запроса — тогда таблицы, помещённые первым запросом, будут видны второму.

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

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

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

В коротких запросах необязательно — платформа очистит менеджер автоматически. В больших пакетах с несколькими тяжёлыми таблицами явное УНИЧТОЖИТЬ после последнего использования снижает потребление памяти и считается хорошей практикой.

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

Чаще всего потому, что отбор указан в секции ГДЕ, а не в параметрах виртуальной таблицы: платформа рассчитывает итоги по всем измерениям, а фильтрует потом. Перенесите условия по измерениям в скобки параметров и задайте период — это главный приём ускорения таких запросов.

Можно ли использовать ПОМЕСТИТЬ в запросе динамического списка?

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

Итог

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

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