Вывод результата запроса в 1С: от конструктора до кода
Содержание
Чтобы вывести запрос в 1С, нужно два действия: составить текст запроса и выполнить его в коде. Текст пишут руками или собирают в конструкторе запроса (вызывается из модуля правой кнопкой мыши), а выполнение сводится к трём строкам — создать объект Запрос, задать Текст и вызвать Выполнить().
Результат запроса сам по себе невидим: его либо обходят выборкой в цикле, либо выгружают в таблицу значений, либо передают в отчёт или на форму. Ниже — все способы на платформе 8.3, с рабочим кодом, разбором временных и пакетных запросов, приёмами отладки и ошибками, на которых чаще всего спотыкаются.
Какими способами выполняют запрос в 1С
Запрос в 1С — это чтение данных из базы на языке, похожем на SQL. Вывести его результат можно четырьмя путями, и выбор зависит от задачи:
- 🧱 Конструктор запроса — визуальная сборка текста мышью, без знания синтаксиса. Подходит новичкам и для сложных соединений.
- ⌨️ Программный вызов в модуле — объект
Запрос, обходВыборкив цикле. Основной способ в обработках и обработчиках документов. - 📊 Выгрузка в таблицу значений — результат целиком попадает в
ТаблицаЗначений, дальше с ним работают как с массивом строк. - 📄 Отчёт или форма — вывод на экран через систему компоновки данных (СКД) или табличный документ.
Внутри любого из этих путей текст запроса одинаков. Меняется только то, как вы получаете и показываете результат. Разберём по порядку.
Как собрать запрос через конструктор запроса
Конструктор нужен, когда синтаксис ещё не в пальцах или запрос объёмный: несколько таблиц, соединения, группировки. Он собирает корректный текст без опечаток.
Порядок вызова в Конфигураторе или в режиме расширения:
- Откройте модуль (общий модуль, модуль обработки, модуль формы).
- Поставьте курсор внутрь пустой строки, где будет текст запроса.
- Нажмите правую кнопку мыши →
Конструктор запроса.... Если в строке ещё нет текста, 1С предложит создать новый запрос.
Откроется окно с вкладками. Основные:
- Таблицы и поля — слева список таблиц конфигурации, перетаскиваете нужные в среднюю колонку, из них поля — в правую.
- Связи — соединения между таблицами (левое, внутреннее), если таблиц больше одной.
- Условия — отбор (аналог
ГДЕ), сюда же задаются параметры. - Группировка — суммы, количества, группировочные поля.
- Порядок — сортировка результата.
- Объединения/Псевдонимы — имена колонок результата.
Отдельно есть Конструктор запроса с обработкой результата. Он вызывается из того же контекстного меню и, кроме текста, сразу вставляет в модуль готовый цикл обхода выборки. Для первого запроса это быстрый старт — не придётся писать обвязку руками.
После ОК конструктор вставит в модуль готовый текст в кавычках с разделителями строк |. Его можно дальше править руками — повторный вызов конструктора на существующем тексте откроет его же для редактирования.
Программный вывод запроса: синтаксис и пример кода
Минимальный рабочий запрос в коде выглядит так:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Номенклатура,
| Номенклатура.Код КАК Код,
| Номенклатура.Артикул КАК Артикул
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| НЕ Номенклатура.ПометкаУдаления
|УПОРЯДОЧИТЬ ПО
| Номенклатура.Наименование";
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить(СтрШаблон("%1 — %2", Выборка.Код, Выборка.Артикул));
КонецЦикла;
Что здесь происходит по шагам:
Новый Запрос— создаём объект запроса.Запрос.Текст— присваиваем текст. Символ|в начале строки — служебный разделитель многострочного текста, его ставит сам конструктор.Выполнить()возвращает объектРезультатЗапроса.Выбрать()даётВыборкуИзРезультатаЗапроса— курсор, которыйСледующий()двигает по строкам.- Внутри цикла поля читаются через точку:
Выборка.Код,Выборка.Артикул.
Поля в цикле доступны ровно под теми именами, которые заданы псевдонимами после КАК в запросе. Если написали Номенклатура.Код КАК Код, обращение будет Выборка.Код. Напишете Выборка.Код1 — получите ошибку на этапе выполнения.
Параметры передают отдельно, не склеивая значения в текст:
Запрос.Текст =
"ВЫБРАТЬ
| Продажи.Номенклатура КАК Номенклатура,
| Продажи.Количество КАК Количество
|ИЗ
| РегистрНакопления.Продажи КАК Продажи
|ГДЕ
| Продажи.Период МЕЖДУ &ДатаНачала И &ДатаКонца";
Запрос.УстановитьПараметр("ДатаНачала", НачалоМесяца(ТекущаяДатаСеанса()));
Запрос.УстановитьПараметр("ДатаКонца", КонецМесяца(ТекущаяДатаСеанса()));
Имя параметра в тексте начинается с &, а в коде пишется без него. На сервере текущую дату берут через ТекущаяДатаСеанса() — это корректный серверный вызов.
Как вывести результат запроса в таблицу значений
Когда результат нужен не для построчного вывода, а для дальнейшей обработки — проще выгрузить его целиком в таблицу значений:
ТаблицаНоменклатуры = Запрос.Выполнить().Выгрузить();
Метод Выгрузить() возвращает ТаблицаЗначений, где колонки повторяют поля запроса (с теми же псевдонимами), а строки — результат. Дальше работаете как с обычной таблицей:
Для Каждой Строка Из ТаблицаНоменклатуры Цикл
Сообщить(Строка.Код);
КонецЦикла;
// количество строк, поиск, выгрузка в массив
Количество = ТаблицаНоменклатуры.Количество();
Найденные = ТаблицаНоменклатуры.НайтиСтроки(Новый Структура("Артикул", "АБ-100"));
Разница между Выбрать() и Выгрузить():
| Способ | Что возвращает | Когда применять |
|---|---|---|
Выбрать() | Курсор, перебор в цикле | Данных много, нужна только обработка по одной строке |
Выгрузить() | Таблицу значений целиком в память | Нужны сортировка, поиск, передача таблицы в другую функцию, вывод на форму |
Выгрузить() держит весь результат в оперативной памяти. Для выборок в сотни тысяч строк это тяжело — тогда перебирайте курсором через Выбрать(), не выгружая всё разом.
Чтобы показать таблицу значений пользователю, положите её в реквизит формы типа ТаблицаЗначений и выведите на форму элементом «Таблица». Данные появятся в табличном виде прямо в окне обработки.
Временные таблицы и пакетные запросы
Когда одного ВЫБРАТЬ мало — результат одного запроса нужен как источник для следующего — применяют временные таблицы и пакеты.
Временная таблица создаётся конструкцией ПОМЕСТИТЬ и живёт, пока существует менеджер временных таблиц:
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Номенклатура КАК Номенклатура,
| СУММА(Товары.Количество) КАК Количество
|ПОМЕСТИТЬ ВремТовары
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК Товары
|СГРУППИРОВАТЬ ПО
| Товары.Номенклатура
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура";
Запрос.Выполнить();
Дальше второй запрос с тем же менеджером читает ВремТовары как обычную таблицу. ИНДЕКСИРОВАТЬ ПО ставит индекс на поле — это ускоряет соединение с большой временной таблицей.
Пакетный запрос — несколько запросов в одном тексте, разделённых точкой с запятой. Выполняются за один проход:
Запрос.Текст =
"ВЫБРАТЬ Товары.Номенклатура, Товары.Количество
|ПОМЕСТИТЬ ВремТовары
|ИЗ Документ.РеализацияТоваровУслуг.Товары КАК Товары;
|
|ВЫБРАТЬ ВремТовары.Номенклатура, ВремТовары.Количество
|ИЗ ВремТовары КАК ВремТовары";
МассивРезультатов = Запрос.ВыполнитьПакет();
ПоследнийРезультат = МассивРезультатов[МассивРезультатов.ВГраница()];
ВыполнитьПакет() возвращает массив результатов — по одному на каждый запрос пакета. Элемент берут по индексу; ВГраница() даёт индекс последнего. Если нужны сами временные таблицы как таблицы значений, используют ВыполнитьПакетСВременнымиТаблицами().
Пакеты удобнее череды отдельных Выполнить(): меньше обращений к базе и наглядная последовательность шагов в одном тексте.
Вывод запроса в отчётах, обработках и на форме
Построчный Сообщить() годится для отладки. Для готового результата на экране есть более опрятные варианты.
- 📈 Система компоновки данных (СКД) — штатный механизм отчётов. Создаёте объект
Отчётили внешний отчёт, в схеме компоновки задаёте тот же запрос, а вывод в табличный документ, диаграмму и группировки СКД собирает сама. Пользователь получает настраиваемый отчёт с отборами и итогами. - 🧰 Внешняя обработка — текст запроса в модуле, результат выгружаете в таблицу значений и показываете на форме элементом «Таблица». Быстрый способ сделать разовую выборку без публикации отчёта.
- 📋 Табличный документ — если нужен печатный вид, результат выводят в
ТабличныйДокументчерез макет. Применяют для печатных форм и выгрузок на печать.
Отдельно про вывод с группировками. Если запрос содержит итоги (ИТОГИ ... ПО), результат читают не плоской выборкой, а по уровням: Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам) даёт верхний уровень, а внутри каждой строки Выборка.Выбрать() открывает её детальные записи. Так строят иерархический вывод — например, номенклатура внутри складов.
Для печатной формы результат выводят в ТабличныйДокумент: берут макет с именованными областями, заполняют область параметрами из строки выборки и выводят её в цикле методом Вывести. Это механизм печати накладных, актов и прайс-листов.
Для регулярных отчётов выбирайте СКД: она сама рисует шапку, итоги и даёт пользователю настройки. Запрос при этом тот же — отличается только обёртка вывода.
Оптимизация и отладка запросов
Медленный запрос чаще всего лечится не железом, а текстом. Базовые правила:
- Не обращайтесь к полям через точку от составных типов (
Документ.Контрагент.Родитель) — платформа добавит лишние соединения. Вынесите нужное во временную таблицу. - Для остатков и оборотов регистров берите виртуальные таблицы (
Остатки,Обороты), а не считайте сумму по таблице движений вручную. - Избегайте
ИЛИв условиях соединения — это тормозит выборку. Разбейте наОБЪЕДИНИТЬ ВСЕ. - Большие временные таблицы индексируйте через
ИНДЕКСИРОВАТЬ ПО. - Не тащите в результат поля, которые не используете.
- Если нужна только часть строк, ограничивайте выборку через
ВЫБРАТЬ ПЕРВЫЕ N— платформа не станет читать всю таблицу. - Соединение больших таблиц делайте через заранее отобранную временную таблицу, а не напрямую с полной таблицей движений.
Для отладки и проверки результата пригодятся:
- Консоль запросов — внешняя обработка, в которой пишут текст запроса, задают параметры и сразу видят результат таблицей, без правки кода конфигурации. Классический инструмент разработчика; поставляется отдельной обработкой.
- Отладчик платформы — поставьте точку останова после
Выполнить()и посмотрите результат через выгрузку в таблицу значений в окне просмотра значения. - Замер производительности — в отладчике запускает подсчёт времени по строкам кода, показывает, сколько заняло именно выполнение запроса.
- План запроса — для серверной базы медленные запросы смотрят средствами СУБД (например, план выполнения на стороне PostgreSQL или MS SQL).
Если запрос работает, но данные «не те» — выгрузите результат в таблицу значений и разберите по полям в отладчике. Чаще всего причина в неверном соединении или потерянном условии отбора, а не в синтаксисе.
Частые ошибки при выводе запроса
Ошибки при выводе запроса почти всегда однотипны и ловятся до запуска.
- ❌ Обращение к полю, которого нет в выборке.
Выборка.Количествопадает, если в тексте нет поля с псевдонимомКоличество. Проверьте имена послеКАК. - ❌ Параметр не установлен. В тексте есть
&ДатаНачала, аУстановитьПараметрдля него не вызван — запрос вернёт пусто или ошибку. Устанавливайте все параметры из текста. - ❌ Склейка значения в текст запроса.
"ГДЕ Код = " + Код— так делать нельзя: ломается на спецсимволах и небезопасно. Всегда через параметр&Код. - ❌ Пустая проверка результата. Перед обходом полезно проверить
Если Результат.Пустой() Тогда ... КонецЕсли;, иначе цикл просто не отработает молча. - ❌ Потерянный менеджер временных таблиц. Второй запрос не видит
ВремТовары, еслиМенеджерВременныхТаблицне назначен обоим запросам (или создан заново).
Частые вопросы
Чем отличается `Выбрать()` от `Выгрузить()`?
Выбрать() возвращает курсор для обхода результата в цикле по одной строке — экономит память. Выгрузить() отдаёт весь результат сразу в таблицу значений — удобно для поиска, сортировки и передачи дальше, но держит данные в памяти.Как передать значение в запрос, чтобы не ломался синтаксис?
&ИмяПараметра, в коде Запрос.УстановитьПараметр("ИмяПараметра", Значение). Склеивать значения в строку текста нельзя.Можно ли в одном запросе получить сразу несколько результатов?
ВЫБРАТЬ, разделённых ;. Выполняется методом ВыполнитьПакет(), который возвращает массив результатов — по одному на каждый запрос пакета.Для чего нужны временные таблицы?
ПОМЕСТИТЬ ИмяТаблицы при назначенном МенеджерВременныхТаблиц. Крупные временные таблицы индексируют через ИНДЕКСИРОВАТЬ ПО для скорости соединений.