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

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

Как писать запросы в 1С 8.3: от простого выбора до пакетных запросов

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

Язык запросов — основной способ получения данных в 1С 8.3. Через него выбираются записи из справочников, документов и регистров, строятся отчёты, заполняются табличные части и динамические списки. Синтаксис напоминает SQL, но оперирует объектами конфигурации, а не физическими таблицами базы данных.

Запрос в коде создаётся объектом Запрос: вы задаёте текст, передаёте параметры и вызываете метод Выполнить(). Результат можно обойти выборкой, выгрузить в таблицу значений или использовать как источник для СКД. Ошибки в запросе проявляются либо сразу — при выполнении, либо косвенно — в виде медленной работы и лишних соединений.

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

Базовый синтаксис: из чего состоит запрос

Минимальный запрос содержит секции ВЫБРАТЬ и ИЗ. В первой перечисляются поля, во второй — источник данных: имя объекта метаданных через точку, например Справочник.Номенклатура или Документ.РеализацияТоваровУслуг.

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

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

"ВЫБРАТЬ

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

| Товары.Код КАК Код

|ИЗ

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

|ГДЕ

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

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

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

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

// обработка строки

КонецЦикла;

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

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

Конструктор запроса: как собрать текст без ручного набора

В модуле установите курсор внутрь строкового литерала, нажмите правую кнопку мыши и выберите «Конструктор запроса». Если текст пустой, конструктор откроется с чистым шаблоном; если запрос уже написан — разберёт его в визуальную форму. Это основной способ не ошибиться в именах таблиц и полей.

На закладке «Таблицы и поля» перетащите нужный объект из дерева базы данных в список таблиц, затем отметьте поля. На закладках «Условия», «Связи», «Группировка», «Порядок» настраиваются отборы, соединения, итоги и сортировка. Кнопка «Запрос» внизу окна показывает итоговый текст.

Конструктор не заменяет понимания синтаксиса: сложные конструкции — вложенные запросы, ВЫБОР КОГДА, работа с иерархией — проще дописать вручную. Практичный подход: каркас собрать конструктором, детали доработать текстом.

Как написать первый запрос
  1. 1
    Определите, какие данные нужны и из какого объекта конфигурации их брать
  2. 2
    В модуле создайте объект Запрос и откройте конструктор запроса
  3. 3
    Выберите таблицу и поля, добавьте условия с параметрами (&Имя)
  4. 4
    Закройте конструктор, установите значения параметров через УстановитьПараметр
  5. 5
    Выполните запрос и проверьте результат выборкой или выгрузкой в таблицу значений

Параметры и условия: как передавать отборы безопасно

Любое значение от пользователя или из кода передаётся в запрос параметром. В тексте параметр начинается с амперсанда: &Контрагент, &ДатаНачала. Значение задаётся методом УстановитьПараметр("Контрагент", КонтрагентСсылка) до вызова Выполнить().

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

Для отбора по списку значений параметру присваивают массив или список значений, а в условии используют оператор В:

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

"ВЫБРАТЬ

| Док.Ссылка

|ИЗ

| Документ.ЗаказПокупателя КАК Док

|ГДЕ

| Док.Контрагент В (&СписокКонтрагентов)

| И Док.Дата МЕЖДУ &Начало И &Конец";

Запрос.УстановитьПараметр("СписокКонтрагентов", МассивКонтрагентов);

Для проверки принадлежности к группе иерархического справочника используйте В ИЕРАРХИИ(&Группа). Для поиска по подстроке — ПОДОБНО "%" + &Фрагмент + "%" (спецсимволы в искомой строке нужно экранировать). Проверка на пустое значение: сравнение с ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка) или функция ЕСТЬ NULL для полей, которые могут быть не заполнены после соединений.

Соединения таблиц: ЛЕВОЕ, ВНУТРЕННЕЕ и когда какое нужно

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

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

Условия соединения пишите максимально полно: связывайте по всем ключевым измерениям. Неполная связь (например, только по номенклатуре, когда регистр ведётся ещё и по складу) размножает строки — результат «распухает», а суммы задваиваются. Это одна из самых коварных ошибок: запрос выполняется без ошибок, но итоги неверны.

После левого соединения проверяйте NULL: функция ЕСТЬNULL(Поле, 0) подставляет значение по умолчанию, а условие Поле ЕСТЬ NULL отбирает строки без пары. Сравнение NULL = 0 не сработает — NULL не равен ничему, включая сам себя.

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

ВНУТРЕННЕЕ

Нужны только строки с парой в обеих таблицах. Быстрее, но «теряет» записи без соответствия

ЛЕВОЕ

Нужны все строки основной таблицы, даже без пары. Требует обработки NULL в полях правой таблицы

ПРАВОЕ / ПОЛНОЕ

Редкие случаи; правое обычно заменяют левым сменой порядка таблиц, полное — при симметричных наборах данных

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

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

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

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

"ВЫБРАТЬ

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

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

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Остатки(

| &ДатаОстатков,

| Склад = &Склад) КАК Остатки";

Запрос.УстановитьПараметр("ДатаОстатков", КонецДня(ДатаОтчета));

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

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

Итоги, группировки и пакетные запросы

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

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

Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;

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

"ВЫБРАТЬ Док.Ссылка, Док.Контрагент

|ПОМЕСТИТЬ ВТ_Документы

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

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

|;

|ВЫБРАТЬ ВТ.Контрагент, СУММА(ТЧ.Сумма) КАК Сумма

|ИЗ ВТ_Документы КАК ВТ

| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Товары КАК ТЧ

| ПО ВТ.Ссылка = ТЧ.Ссылка

|СГРУППИРОВАТЬ ПО ВТ.Контрагент";

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

Проверка результата и типичные ошибки

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

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

Типичные ошибки в запросах 1С
01
Отбор виртуальной таблицы в секции ГДЕ вместо параметров — остатки считаются по всей базе, запрос тормозит
02
Неполное условие соединения — строки размножаются, суммы задваиваются без сообщения об ошибке
03
Соединение с табличной частью без необходимости — каждая строка документа дублируется на число строк ТЧ
04
Запрос в цикле вместо одного запроса с соединением — сотни обращений к СУБД вместо одного
05
Сравнение с NULL через равенство — условие никогда не выполняется, записи теряются
06
Выборка ПЕРВЫЕ без УПОРЯДОЧИТЬ — какая именно запись вернётся, не гарантировано

Частые вопросы

Чем запрос отличается от обхода справочника через Выбрать()?

Метод объекта Выбрать() читает записи по одной и для каждой может тянуть все поля. Запрос забирает только нужные поля одним обращением к СУБД и позволяет фильтровать и соединять данные на стороне сервера. Для чтения данных запрос почти всегда предпочтительнее; объектный обход оправдан, когда нужно изменять объекты.

Как получить только одну строку результата?

Используйте конструкцию ВЫБРАТЬ ПЕРВЫЕ 1 и обязательно добавьте УПОРЯДОЧИТЬ ПО, иначе платформа вернёт произвольную запись. В коде затем проверьте Выборка.Следующий() — если результат пустой, метод вернёт Ложь.

Можно ли выполнять запросы к данным другой информационной базы?

Язык запросов работает только с текущей базой. Для доступа к другой базе используют COM-соединение, веб-сервисы, HTTP-сервисы или планы обмена; внутри внешнего соединения запрос пишется по тем же правилам, но выполняется в контексте той базы.

Почему запрос с соединением возвращает больше строк, чем в документе?

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

Как отладить запрос, если он не возвращает данные?

Уберите все условия, кроме одного, и добавляйте их по одному — так найдётся условие, которое отсекает всё. Проверьте значения параметров (тип и заполненность), пометки удаления, даты (время в границах периода) и NULL после левых соединений. Консоль запросов ускоряет такую проверку, позволяя менять текст без перезапуска кода.

Что такое СКД и когда она заменяет запрос?

Система компоновки данных — механизм построения отчётов, где запрос является источником данных, а группировки, отборы и оформление настраиваются отдельно, в том числе пользователем. Для отчётов с гибкими настройками СКД предпочтительнее ручной обработки выборки; для служебных выборок в коде достаточно обычного объекта Запрос.

Итог

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

Запрос состоит из ВЫБРАТЬ / ИЗ / ГДЕ, собирается конструктором, значения передаются параметрами. Соединения требуют полных условий и обработки NULL. Отборы виртуальных таблиц — в их параметрах. Сложные задачи решайте пакетными запросами с временными таблицами, а результат всегда проверяйте на реальных данных.