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