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