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

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

Особое внимание уделим практическим примерам — каждый раздел содержит реальные случаи из разработки, которые можно адаптировать под свои задачи. А в конце статьи вы найдёте ответы на частые вопросы и рекомендации по дальнейшему изучению темы.

1. Основы синтаксиса запросов в 1С

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

Базовая структура запроса выглядит так:

ВЫБРАТЬ

[Поля]

ИЗ

[ИсточникДанных]

ГДЕ

[УсловияОтбора]

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

[ПоляСортировки]

Пример простейшей выборки из справочника Номенклатура:

ВЫБРАТЬ

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

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

ИЗ

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

ГДЕ

Номенклатура.ЭтоГруппа = ЛОЖЬ

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

Товар

  • 📌 ВЫБРАТЬ — указывает, какие поля нужно извлечь. Можно использовать псевдонимы (например, КАК Товар).
  • 📌 ИЗ — источник данных (справочник, документ, регистр и т.д.). Обязательно указывать псевдоним (КАК Номенклатура).
  • 📌 ГДЕ — условия отбора. В используются логические операторы (=, <>, И, ИЛИ).
  • 📌 УПОРЯДОЧИТЬ ПО — сортировка результата. По умолчанию — по возрастанию (ВОЗР), для убывания используйте УБЫВ.
📊 Какой источник данных вы чаще всего используете в запросах?
Справочники
Документы
Регистры
Виртуальные таблицы

2. Работа с виртуальными таблицами

Одной из мощнейших возможностей являются виртуальные таблицы. Они позволяют получать данные из регистров накопления, бухгалтерии или расчётов без необходимости писать сложные соединения (ОБЪЕДИНИТЬ). Виртуальные таблицы автоматически учитывают движения документов и актуальное состояние регистров.

Примеры виртуальных таблиц:

  • 📊 РегистрНакопления.ОстаткиТоваров.Остатки() — текущие остатки товаров на складах.
  • 📊 РегистрБухгалтерии.ХозРасчетный.Обороты() — обороты по счётам за период.
  • 📊 Документ.РеализацияТоваровУслуг.Операции() — операции, сформированные документом.

Пример запроса к виртуальной таблице остатков:

ВЫБРАТЬ

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

ОстаткиТоваров.КоличествоОстаток КАК Остаток,

ОстаткиТоваров.Склад

ИЗ

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

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

Склад В (&СписокСкладов)

) КАК ОстаткиТоваров

ГДЕ

ОстаткиТоваров.КоличествоОстаток > 0

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

Особенности работы с виртуальными таблицами:

Тип таблицы Пример вызова Что возвращает
Остатки Остатки(&Дата) Актуальные остатки на указанную дату
Обороты Обороты(&Начало, &Конец) Обороты за период (приход/расход)
ОстаткиИОбороты ОстаткиИОбороты(&Начало, &Конец) Остатки на начало/конец периода + обороты
💡

Для ускорения работы с виртуальными таблицами используйте предопределённые данные (например, НачалоДня() или КонецДня()) вместо произвольных дат.

3. Соединение таблиц: ОБЪЕДИНИТЬ и ЛЕВОЕ СОЕДИНЕНИЕ

Для извлечения данных из нескольких источников используются операции соединения. В доступны:

  • 🔗 ОБЪЕДИНИТЬ — аналог UNION в SQL. Объединяет результаты нескольких запросов.
  • 🔗 ЛЕВОЕ СОЕДИНЕНИЕ — аналог LEFT JOIN. Возвращает все записи из левой таблицы и соответствующие из правой.
  • 🔗 ВНУТРЕННЕЕ СОЕДИНЕНИЕ — аналог INNER JOIN. Возвращает только совпадающие записи.

Пример ЛЕВОГО СОЕДИНЕНИЯ для связывания справочника Номенклатура и регистра ЦеныНоменклатуры:

ВЫБРАТЬ

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

ЦеныНоменклатуры.Цена КАК Цена

ИЗ

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

ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&ДатаЦен) КАК ЦеныНоменклатуры

ПО Номенклатура.Ссылка = ЦеныНоменклатуры.Номенклатура

ГДЕ

Номенклатура.ЭтоГруппа = ЛОЖЬ

Ключевые моменты при соединении:

  • 🔍 Всегда указывайте условие соединения (ПО), иначе получите декартово произведение.
  • 🔍 Для ЛЕВОГО СОЕДИНЕНИЯ поля из правой таблицы могут содержать NULL, если нет совпадений.
  • 🔍 Используйте псевдонимы (КАК) для удобства чтения.
⚠️ Внимание: При соединении больших таблиц (Документ.РеализацияТоваровУслуг и РегистрНакопления.Продажи) всегда ограничивайте период выборки, иначе запрос может выполняться часами.

Ограничен ли период выборки?|Есть ли индексы по полям соединения?|Используются ли псевдонимы для таблиц?|Проверены ли права доступа к данным?-->

4. Группировка, агрегатные функции и условия (ГДЕ vs ИМЕЮЩИЕ)

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

  • 📈 СУММА() — сумма значений.
  • 📈 КОЛИЧЕСТВО() — количество строк.
  • 📈 МАКСИМУМ()/МИНИМУМ() — крайние значения.
  • 📈 СРЕДНЕЕ() — среднее арифметическое.

Пример запроса с группировкой продаж по контрагентам:

ВЫБРАТЬ

Реализация.Контрагент КАК Покупатель,

СУММА(Реализация.СуммаДокумента) КАК ИтогоПродаж,

КОЛИЧЕСТВО(*) КАК КоличествоДокументов

ИЗ

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

ГДЕ

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

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

Покупатель

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

ИтогоПродаж УБЫВ

Важное отличие от SQL: в для фильтрации сгруппированных данных используется ИМЕЮЩИЕ, а не ГДЕ. Например, чтобы отобрать только покупателей с суммой продаж > 100 000:

ИМЕЮЩИЕ

СУММА(Реализация.СуммаДокумента) > 100000

В запросах 1С нельзя использовать агрегатные функции в секции ГДЕ — это приведёт к ошибке. Всегда применяйте ИМЕЮЩИЕ для фильтрации после группировки.

5. Подзапросы и временные таблицы

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

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

ВЫБРАТЬ

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

ИЗ

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

ГДЕ

Номенклатура.Ссылка В (

ВЫБРАТЬ РАЗЛИЧНЫЕ

Реализация.Номенклатура

ИЗ

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

ГДЕ

Реализация.Ссылка.Дата МЕЖДУ НачалоМесяца(ТЕКУЩАЯДАТА()) И КонецМесяца(ТЕКУЩАЯДАТА())

)

Временные таблицы создаются с помощью конструкции ПОМЕСТИТЬ.. ВТ:

ВЫБРАТЬ

Реализация.Контрагент КАК Покупатель,

СУММА(Реализация.СуммаДокумента) КАК Сумма

ПОМЕСТИТЬ ВТ_ПродажиПоКонтрагентам

ИЗ

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

ГДЕ

Реализация.Дата > НачалоГода(ТЕКУЩАЯДАТА())

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

Покупатель

ИНДЕКСИРОВАТЬ ПО

Покупатель

;

////////////////////////////////////////////////

ВЫБРАТЬ

ВТ_ПродажиПоКонтрагентам.Покупатель,

ВТ_ПродажиПоКонтрагентам.Сумма

ИЗ

ВТ_ПродажиПоКонтрагентам КАК ВТ_ПродажиПоКонтрагентам

ГДЕ

ВТ_ПродажиПоКонтрагентам.Сумма > 500000

Преимущества временных таблиц:

  • ⚡ Ускоряют выполнение сложных запросов за счёт промежуточного сохранения данных.
  • ⚡ Позволяют использовать индексы (ИНДЕКСИРОВАТЬ ПО).
  • ⚡ Упрощают чтение кода при разбиении большого запроса на части.
⚠️ Внимание: Временные таблицы существуют только в рамках одного запроса. Если вам нужно сохранить данные для дальнейшей обработки в коде, используйте РезультатЗапроса.Выгрузить().
Когда использовать подзапросы, а когда — временные таблицы?

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

6. Оптимизация запросов: индексы, планы выполнения и типичные ошибки

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

1. Использование индексов

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

  • 🔍 Указывать индексируемые поля в условиях ГДЕ.
  • 🔍 Избегать функций над полями в условиях (например, ГДЕ ЛЕВ(Поле, 3) = "АБВ" — это заблокирует использование индекса).

2. Анализ плана выполнения

Чтобы понять, почему запрос работает медленно, используйте ОбъяснитьЗапрос():

План = Запрос.Объяснить();

План.Вывести();

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

3. Типичные ошибки, тормозящие запросы

Ошибка Пример Как исправить
Выборка всех полей (*) ВЫБРАТЬ * ИЗ Документ.Реализация Указывайте только нужные поля
Отсутствие ограничения по дате ВЫБРАТЬ.. ИЗ РегистрНакопления.Продажи Всегда ограничивайте период
Использование РАЗЛИЧНЫЕ без необходимости ВЫБРАТЬ РАЗЛИЧНЫЕ Номенклатура Убирайте РАЗЛИЧНЫЕ, если не нужны уникальные значения

4. Память и объём данных

Если запрос возвращает большое количество строк, используйте ПАКЕТНЫЙ режим или разбивайте выборку на части:

ВЫБРАТЬ ПЕРВЫЕ 1000

..

ИЗ

..

;

💡

Всегда тестируйте запросы на небольших объёмах данных перед запуском на рабочей базе. Используйте конструктор запросов в конфигураторе для визуальной отладки.

7. Практические примеры: отчёты, аналитика, сложные выборки

Рассмотрим реальные сценарии, с которыми сталкиваются разработчики.

Пример 1: Отчёт по продажам с детализацией по менеджерам

ВЫБРАТЬ

Реализация.Менеджер КАК Менеджер,

Реализация.Контрагент КАК Покупатель,

СУММА(Реализация.СуммаДокумента) КАК СуммаПродаж,

КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Реализация.Номенклатура) КАК КоличествоТоваров

ИЗ

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

ГДЕ

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

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

Менеджер,

Покупатель

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

СуммаПродаж УБЫВ

Пример 2: Поиск дублей в справочнике Контрагенты по ИНН

ВЫБРАТЬ

Контрагенты.ИНН КАК ИНН,

СТРОКА(КОЛИЧЕСТВО(*)) КАК КоличествоДублей,

ВЫБОР

КОГДА КОЛИЧЕСТВО(*) > 1

ТОГДА "Дубль"

ИНАЧЕ "Уникальный"

КОНЕЦ КАК Статус

ИЗ

Справочник.Контрагенты КАК Контрагенты

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

ИНН

ИМЕЮЩИЕ

КОЛИЧЕСТВО(*) > 1

Пример 3: Анализ динамики продаж по месяцам

ВЫБРАТЬ

ВЫРАЗИТЬ(Реализация.Дата КАК ДАТАГОДМЕСЯЦ) КАК Месяц,

СУММА(Реализация.СуммаДокумента) КАК СуммаПродаж

ИЗ

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

ГДЕ

Реализация.Дата МЕЖДУ НачалоГода(ТЕКУЩАЯДАТА()) И ТЕКУЩАЯДАТА()

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

Месяц

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

Месяц

Для визуализации таких данных удобно использовать систему компоновки данных (СКД), которая позволяет строить диаграммы и сводные таблицы на основе запросов.

8. Отладка и диагностика ошибок

Даже опытные разработчики сталкиваются с ошибками в запросах. Рассмотрим типичные проблемы и способы их решения.

1. Синтаксические ошибки

Платформа подсвечивает ошибки при проверке синтаксиса, но иногда сообщения бывают неявными. Например:

  • 🛑 Ошибка в выражении запроса: Неопознанное имя 'Поле' — опечатка в имени поля или таблицы.
  • 🛑 Недопустимое использование агрегатной функции в этом контексте — попытка использовать СУММА() в секции ГДЕ.

2. Ошибки выполнения

Если запрос выполняется долго или падает с ошибкой Превышено время ожидания, проверьте:

  • 🔍 Ограничен ли период выборки?
  • 🔍 Есть ли индексы по полям в условиях?
  • 🔍 Не слишком ли много соединений (ОБЪЕДИНИТЬ)?

3. Некорректные результаты

Если запрос возвращает не те данные, которые вы ожидаете:

  • 🔍 Проверьте условия в секции ГДЕ (возможно, неверное сравнение дат или статусов).
  • 🔍 Убедитесь, что используете правильную виртуальную таблицу (например, Остатки() вместо Обороты()).
  • 🔍 Для регистров проверьте, не сбились ли движения документов (используйте Тестирование и исправление в конфигураторе).

Для диагностики используйте:

  • 🛠️ ОбъяснитьЗапрос() — покажет план выполнения.
  • 🛠️ Запрос.Выполнить().Выгрузить() — экспортирует результат в таблицу значений для анализа.
  • 🛠️ Журнал регистрации — там могут быть ошибки выполнения запроса.
⚠️ Внимание: Если запрос работает в конструкторе, но падает в коде, проверьте права пользователя на доступ к данным. Например, может отсутствовать право на чтение регистра накопления.

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

Как узнать, какие поля доступны в виртуальной таблице?

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

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

Вероятные причины:

  • Неверные условия в секции ГДЕ (например, сравнение с NULL через = вместо ЕСТЬ NULL).
  • Ошибка в соединении таблиц (нет совпадающих записей).
  • Для виртуальных таблиц неверно указаны параметры (например, дата вне диапазона движений).

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

Как ускорить запрос, который выполняется больше минуты?

Способы оптимизации:

  1. Ограничьте период выборки (например, вместо года берите последний месяц).
  2. Добавьте индексы по полям, используемым в условиях.
  3. Разбейте запрос на части с использованием временных таблиц.
  4. Используйте ПАКЕТНЫЙ режим для больших выборок.

Если ничего не помогает, рассмотрите возможность денормализации данных или использования внешних отчётов.

Можно ли в запросе использовать свои функции?

Нет, в тексте запроса можно использовать только встроенные функции платформы (например, НАЧАЛОПЕРИОДА(), ВЫРАЗИТЬ()). Для кастомной логики используйте обработку результата запроса в коде на .

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

Используйте следующий код:

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

Таблица = Результат.Выгрузить();

Таблица.Записать("C:\Temp\Отчёт.xlsx", ТипФайлаExcel.Xlsx);

Для красивого оформления используйте систему компоновки данных (СКД) с выводом в Excel.