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