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