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