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