К статье
Практический материал

Разработка и Конфигурация · 13 мин

Как писать запросы в 1С: практическое руководство

Практическое руководство по языку запросов 1С: выборка, соединения, группировки, виртуальные таблицы, параметры и проверка результата в консоли запросов.

Язык запросов 1С — основной инструмент для получения данных из информационной базы: он используется в отчётах, обработках, динамических списках и при программной выборке данных. Синтаксис напоминает SQL, но имеет собственные особенности: обращение к объектам метаданных вместо таблиц СУБД, встроенные виртуальные таблицы, конструкции итогов и разрезов периодов.

Ошибка в запросе редко приводит к падению программы, но почти всегда — к неверным цифрам в отчёте или к медленной работе базы. Поэтому писать запрос нужно не наугад, а по понятному алгоритму: определить источник данных, отобрать нужные поля, наложить условия, соединить таблицы и проверить результат на тестовых данных.

Ниже разобраны базовые конструкции языка, работа с параметрами и виртуальными таблицами, способы отладки и типичные ошибки, из-за которых запросы возвращают лишние строки или работают медленно.

Где выполнять и отлаживать запрос

Прежде чем встраивать запрос в код, его нужно написать и проверить отдельно. Для этого используют консоль запросов — внешнюю обработку, которая позволяет выполнить произвольный запрос и сразу увидеть результат. Консоль входит в состав стандартных инструментов разработчика (ИР) или поставляется как отдельная обработка.

Второй вариант — конструктор запроса, встроенный в конфигуратор. Он вызывается из модуля правой кнопкой мыши (Конструкторы → Конструктор запроса) и позволяет собрать запрос мышью: выбрать таблицы, поля, условия и соединения. Конструктор полезен на этапе обучения и для сложных соединений, но опытные разработчики чаще пишут текст вручную.

Третий способ проверки — временная обработка с выводом результата в таблицу значений. Это удобно, когда нужно проверить запрос с конкретными параметрами, которые вычисляются в коде.

Порядок разработки запроса
  1. 1
    Откройте консоль запросов и определите, из каких таблиц брать данные
  2. 2
    Напишите минимальный запрос: ВЫБРАТЬ поля ИЗ таблица — убедитесь, что данные возвращаются
  3. 3
    Добавьте условия через ГДЕ и параметры (&Параметр)
  4. 4
    Добавьте соединения и группировки, проверяя результат после каждого шага
  5. 5
    Перенесите текст в модуль, заполните параметры через Запрос.УстановитьПараметр()
  6. 6
    Проверьте результат на граничных случаях: пустой период, отсутствие данных, большие объёмы

Базовая структура запроса: ВЫБРАТЬ, ИЗ, ГДЕ

Минимальный запрос состоит из трёх конструкций. Ключевое слово ВЫБРАТЬ задаёт список полей, ИЗ — источник данных (таблица метаданных), ГДЕ — условия отбора. Источником выступает объект конфигурации: справочник, документ, регистр сведений или регистр накопления.

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Номенклатура.Ссылка КАК Товар,

| Номенклатура.Код КАК Код,

| Номенклатура.Наименование КАК Наименование

|ИЗ

| Справочник.Номенклатура КАК Номенклатура

|ГДЕ

| НЕ Номенклатура.ПометкаУдаления";

РезультатЗапроса = Запрос.Выполнить();

Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл

Сообщить(Выборка.Наименование);

КонецЦикла;

Обратите внимание на несколько правил. Псевдоним таблицы (КАК Номенклатура) делает текст читаемым и обязателен при соединениях. Поля перечисляются явно — конструкция «ВЫБРАТЬ *» в языке 1С отсутствует, а выбирать все поля подряд не нужно: это замедляет выполнение и усложняет поддержку. Условие на пометку удаления — стандартная практика, если помеченные объекты не должны попадать в выборку.

Результат запроса обрабатывается двумя способами: метод Выбрать() возвращает выборку для последовательного обхода в цикле, а метод Выгрузить() — таблицу значений, удобную для произвольного доступа к строкам и сортировки.

Условия и параметры запроса

Отборы в запросе задаются в секции ГДЕ. Значения условий почти всегда передаются через параметры — имена, начинающиеся с символа «&». Параметр объявляется в тексте запроса, а его значение устанавливается методом УстановитьПараметр до выполнения.

Запрос.Текст =

"ВЫБРАТЬ

| Док.Ссылка КАК Документ,

| Док.СуммаДокумента КАК Сумма

|ИЗ

| Документ.РеализацияТоваровУслуг КАК Док

|ГДЕ

| Док.Дата МЕЖДУ &НачалоПериода И &КонецПериода

| И Док.Контрагент = &Контрагент

| И Док.Проведен";

Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДатаСеанса()));

Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(ТекущаяДатаСеанса()));

Запрос.УстановитьПараметр("Контрагент", ВыбранныйКонтрагент);

Для отбора по списку значений используется оператор В: «Док.Склад В (&СписокСкладов)». В параметр передаётся массив или список значений. Для поиска по части строки применяется ПОДОБНО с шаблоном: «Номенклатура.Наименование ПОДОБНО ""%"" + &СтрокаПоиска + ""%"""» — учтите, что такой поиск не использует индекс и на больших таблицах работает медленно.

Категорически избегайте подстановки значений прямо в текст запроса через конкатенацию строк. Помимо риска ошибок с типами (даты, строки с кавычками), это мешает платформе кэшировать план запроса и усложняет отладку.

Типичные ошибки с параметрами
01
Подстановка значений конкатенацией строк — запрос падает на данных с кавычками и датами, план не кэшируется
02
Параметр объявлен в тексте, но не установлен через УстановитьПараметр — ошибка «Параметр не найден» при выполнении
03
Передача в параметр значения неверного типа (строка вместо ссылки) — условие молча не срабатывает, результат пустой

Соединение таблиц

Данные редко лежат в одной таблице: шапка документа хранится отдельно от табличной части, остатки — в регистре, а свойства товара — в справочнике. Связь таблиц выполняется соединениями. В языке 1С доступны ЛЕВОЕ, ПРАВОЕ, ВНУТРЕННЕЕ и ПОЛНОЕ соединения.

Запрос.Текст =

"ВЫБРАТЬ

| Товары.Номенклатура КАК Товар,

| Товары.Количество КАК Количество,

| Спр.Артикул КАК Артикул

|ИЗ

| Документ.РеализацияТоваровУслуг.Товары КАК Товары

| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Спр

| ПО Товары.Номенклатура = Спр.Ссылка

|ГДЕ

| Товары.Ссылка = &Документ";

Левое соединение возвращает все строки левой таблицы, даже если в правой нет пары — тогда поля правой таблицы будут NULL. Внутреннее соединение возвращает только строки, где пара нашлась в обеих таблицах. Практическое правило: если дополнительные данные не обязательны (артикул, характеристика), используйте левое соединение; если строка без пары бессмысленна — внутреннее.

Частая ловушка — дублирование строк. Если в правой таблице условию связи соответствует несколько записей (например, несколько записей регистра сведений на один товар), каждая строка левой таблицы умножится. В отчётах это проявляется как завышенные суммы. Проверяйте результат на документе, где заведомо известны цифры.

Виртуальные таблицы регистров

Регистры накопления и сведений имеют виртуальные таблицы — предвычисленные представления данных: остатки, обороты, срез первых и срез последних. Использовать их нужно вместо самостоятельной группировки физической таблицы регистра: виртуальные таблицы быстрее и проще.

Запрос.Текст =

"ВЫБРАТЬ

| Остатки.Номенклатура КАК Товар,

| Остатки.Склад КАК Склад,

| Остатки.КоличествоОстаток КАК Остаток

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад) КАК Остатки";

Запрос.УстановитьПараметр("Период", КонецДня(ТекущаяДатаСеанса()));

Запрос.УстановитьПараметр("Склад", ВыбранныйСклад);

Параметры виртуальной таблицы указываются в скобках после её имени: период расчёта и условия отбора. Важный нюанс: отбор лучше задавать именно в параметрах виртуальной таблицы, а не в секции ГДЕ. Условие в параметрах применяется до вычисления остатков и работает заметно быстрее на больших регистрах.

Для регистра сведений аналогичная задача решается таблицами СрезПоследних и СрезПервых — они возвращают актуальные значения измерений на заданную дату. Именно срез последних используют, чтобы получить, например, цену товара или ответственного сотрудника на дату документа.

Маршрут решения

Как выбрать источник данных

Нужны текущие остатки или остатки на датуРегистрНакопления.Имя.Остатки(&Период, отбор)
Нужны приход и расход за интервалРегистрНакопления.Имя.Обороты(&Начало, &Конец, , отбор)
Нужно актуальное значение реквизита на дату (цена, курс, статус)РегистрСведений.Имя.СрезПоследних(&Период, отбор)
Нужны сами документы с реквизитамиТаблица документа с условием на период и Проведен = Истина

Группировки, итоги и проверка результата

Для агрегации данных используется секция СГРУППИРОВАТЬ ПО с агрегатными функциями: СУММА, КОЛИЧЕСТВО, МАКСИМУМ, МИНИМУМ, СРЕДНЕЕ. Все неагрегатные поля из списка ВЫБРАТЬ обязаны входить в группировку — иначе запрос не выполнится.

"ВЫБРАТЬ

| Продажи.Номенклатура КАК Товар,

| СУММА(Продажи.КоличествоОборот) КАК Продано,

| СУММА(Продажи.СуммаОборот) КАК Выручка

|ИЗ

| РегистрНакопления.Продажи.Обороты(&Начало, &Конец, , ) КАК Продажи

|СГРУППИРОВАТЬ ПО

| Продажи.Номенклатура

|УПОРЯДОЧИТЬ ПО

| Выручка УБЫВ"

Для иерархических итогов (например, по группам номенклатуры) применяется секция ИТОГИ ПО. При обходе выборки с итогами используется ОбходРезультатаЗапроса.ПоГруппировкам. Сортировка задаётся секцией УПОРЯДОЧИТЬ ПО, для вложенных табличных частей — конструкцией УПОРЯДОЧИТЬ ПО с указанием полей ссылки.

Проверка результата — обязательный этап. Возьмите один документ или один товар, посчитайте ожидаемые цифры вручную по базе и сравните с результатом запроса. Затем проверьте граничные случаи: период без данных, отбор по несуществующему параметру, отмена условий.

Контрольные точки

Как проверить результат запроса

Количество строк
Норма

Совпадает с числом записей в исходной таблице при тех же условиях

Тревожный признак

Строк больше — вероятно дублирование при соединении

Суммы по известному документу
Норма

Совпадают с данными документа в базе

Тревожный признак

Суммы завышены кратно — умножение строк из-за соединения

Поведение при пустых данных
Норма

Запрос возвращает пустой результат без ошибок

Тревожный признак

Ошибка выполнения или строки с NULL там, где их быть не должно

Скорость выполнения
Норма

Запрос на рабочем объёме выполняется за приемлемое время

Тревожный признак

Заметная пауза — проверьте отборы в параметрах виртуальных таблиц и индексы

Производительность и ограничения

Медленный запрос — обычно результат нескольких типовых причин. Первая — отбор по неиндексированным полям: условия на дату документа или ссылку работают быстро, а поиск ПОДОБНО по наименованию перебирает всю таблицу. Вторая — условия над виртуальными таблицами в секции ГДЕ вместо параметров самой таблицы. Третья — выборка лишних полей и соединение таблиц, данные которых не используются.

Конструкция РАЗЛИЧНЫЕ убирает дубли строк, но не должна маскировать ошибки соединений: если дубли появились из-за неправильной связи, правильное решение — исправить соединение. Секция ПЕРВЫЕ N ограничивает число строк и полезна для подбора и автоподстановки, но не заменяет полноценный отбор.

Для сложной логики применяются временные таблицы: часть данных выбирается оператором ПОМЕСТИТЬ во временную таблицу, а следующий запрос пакета использует её как источник. Это упрощает текст и часто ускоряет выполнение, так как промежуточный результат материализуется один раз. Пакет завершается уничтожением временных таблиц или установкой МенеджерВременныхТаблиц.

Если запрос в консоли работает быстро, а в рабочей базе медленно — сравните объёмы данных и убедитесь, что параметры передаются с теми же типами. Разница почти всегда объясняется либо объёмом, либо неявным преобразованием типов в условии.
ПЗ
Практическое замечание

Частые вопросы по запросам 1С

Чем запрос 1С отличается от SQL?

Запрос 1С оперирует объектами метаданных (справочниками, документами, регистрами), а не физическими таблицами СУБД. Платформа сама транслирует текст в SQL конкретной СУБД. В языке есть конструкции, которых нет в SQL: виртуальные таблицы, итоги, иерархия справочников. Прямой доступ к базе средствами SQL для изменения данных запрещён — это нарушает логику платформы и может повредить данные.

Почему запрос возвращает пустой результат, хотя данные есть?

Чаще всего причина в типе параметра: передана строка вместо ссылки, или дата без времени при сравнении с датой документа. Проверьте также условие на проведённость документов и пометку удаления. Выполните запрос в консоли, убирая условия по одному, — так локализуется проблемное.

Как получить цену товара на дату документа?

Используйте виртуальную таблицу СрезПоследних регистра сведений цен с параметром-периодом, равным дате документа, и отбором по номенклатуре. Затем соедините срез с таблицей товаров левым соединением. Условия отбора задавайте в параметрах среза, а не в секции ГДЕ.

Что делать, если запрос выполняется очень долго?

Проверьте, вынесены ли отборы в параметры виртуальных таблиц, не используется ли ПОДОБНО по большим таблицам, нет ли соединений без условия связи. Уберите неиспользуемые поля и таблицы. Для сложной логики разбейте запрос на пакет с временными таблицами. Анализ плана запроса доступен в технологическом журнале.

Можно ли изменять данные запросом?

Нет. Язык запросов 1С предназначен только для чтения данных. Изменение выполняется объектными средствами: через получение объекта методом ПолучитьОбъект(), изменение реквизитов и вызов Записать(). Попытки обойти это прямыми запросами к СУБД приводят к рассогласованию служебных таблиц и повреждению базы.

Зачем нужны временные таблицы и как их использовать?

Временная таблица создаётся оператором ПОМЕСТИТЬ ИмяТаблицы в тексте запроса и существует в рамках менеджера временных таблиц. Она полезна, когда один и тот же отбор нужен в нескольких частях пакета запросов или когда сложное условие проще вычислить заранее. После использования таблицу удаляют оператором УНИЧТОЖИТЬ.

Итог

Что важно запомнить

Пишите запрос сначала в консоли, добавляя конструкции по шагам и проверяя результат. Отборы передавайте только через параметры, условия для виртуальных таблиц — в их параметрах, а не в ГДЕ. Проверяйте итоговые суммы на заведомо известных данных: дубли строк при соединениях — самая частая причина неверных отчётов.