Составить программу запроса

Учимся составить программу запроса без боли и скучных лекций. Разбираем JOIN, WHERE и подзапросы на живых примерах. Пиши код, который реально работает!

Бесплатная консультация юриста

+7 (800) 301-07-30

Реклама jurik.ru

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

Данная статья подробно разбирает подходы‚ инструменты и лучшие практики создания «программы запроса» — от использования объекта СхемаЗапроса до выполнения и обработки результатов;


Два подхода к составлению запроса в 1С

Платформа предлагает два принципиально разных пути получения текста запроса:

  • Визуальный (декларативный): Использование встроенного Конструктора запросов в конфигураторе. Разработчик мышкой выбирает таблицы‚ поля‚ связи‚ условия. Платформа генерирует синтаксически верный текст. Подходит для фиксированных алгоритмов.
  • Программный (императивный): Формирование текста запроса или его объектной модели в коде на встроенном языке. Это дает полную гибкость: изменение структуры запроса в зависимости от условий‚ прав доступа‚ параметров отчета.

Важно: Даже если вы пишете программу запроса‚ знание синтаксиса языка запросов и умение пользоваться визуальным конструктором для прототипирования остаются обязательными навыками.


Объектная модель запроса: СхемаЗапроса (QuerySchema)

Начиная с версий 1С 8.3‚ для программного построения запроса появился мощный объект — СхемаЗапроса. Он позволяет оперировать не строками (конкатенацией)‚ а типизированными объектами встроенного языка.

Основные преимущества СхемыЗапроса:

  1. Типобезопасность: Ошибки в именах таблиц и полей обнаруживаются на этапе компиляции/проверки конфигурации‚ а не в рантайме.
  2. Структурированность: Легко добавлять/удалять поля‚ таблицы‚ условия‚ группировки в циклах.
  3. Автоматическое форматирование: Метод ПолучитьТекст генерирует красивый‚ отформатированный SQL-подобный код.
  4. Поддержка пакетных запросов: Удобное управление временными таблицами.

Ключевые объекты модели:

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

Пошаговый алгоритм: Программа составления запроса с СхемойЗапроса

Рассмотрим классический пример: Получение остатков товаров с последними ценами продажи (аналог примера из документации: документ РасходТовара + срез последних регистра ЦеныТоваров).

Шаг 1. Инициализация схемы и пакета

// Создаем корневую схему
Схема = Новый СхемаЗапроса;

// Обязательно создаем пакет (даже если запрос один)
Пакет = Схема.Пакеты.Добавить;
Пакет.Имя = "ОсновнойПакет";

Шаг 2. Добавление основных таблиц (Источников данных)

// 1. Табличная часть документа РасходТовара
ТаблицаРасход = Пакет.Таблицы.Добавить(Тип("СхемаЗапросаТаблица"));
ТаблицаРасход.Имя = "РасходТовараТовары";
ТаблицаРасход.Псевдоним = "Расход";
ТаблицаРасход.ВидТаблицы = ВидТаблицыСхемыЗапроса.ТаблицаБД;
ТаблицаРасход.ИмяТаблицыБД = "Документ.РасходТовара.Товары"; // Метаданные

// 2. Срез последних регистра сведений ЦеныТоваров
ТаблицаЦены = Пакет.Таблицы.Добавить(Тип("СхемаЗапросаТаблица"));
ТаблицаЦены.Имя = "ЦеныТоваровСрез";
ТаблицаЦены.Псевдоним = "Цены";
ТаблицаЦены.ВидТаблицы = ВидТаблицыСхемыЗапроса.ВиртуальнаяТаблица;
ТаблицаЦены.ИмяВиртуальнойТаблицы = "РегистрСведений.ЦеныТоваров.СрезПоследних";
ТаблицаЦены.ПараметрыВиртуальнойТаблицы.УстановитьЗначениеПараметра("ДатаСреза"‚ ТекущаяДата);

Шаг 3. Настройка связей (Соединений)

Здесь программный подход выигрывает у конкатенации строк: мы явно задаем поля связи.

// Создаем Левое соединение: Расход ТОВАРЫ -> Цены
Соединение = ТаблицаРасход.Соединения.Добавить(Тип("СхемаЗапросаСоединение"));
Соединение.ВидСоединения = ВидСоединенияСхемыЗапроса.Левое;
Соединение.ПраваяТаблица = ТаблицаЦены;
Соединение.ПсевдонимПравойТаблицы = "Цены";

// Условия связи (ПО)
УсловиеТовар = Соединение.Условия.Добавить(Тип("СхемаЗапросаУсловие"));
УсловиеТовар.ЛевоеВыражение = Новый СхемаЗапросаПоле("Расход.Номенклатура");
УсловиеТовар.ПравоеВыражение = Новый СхемаЗапросаПоле("Цены.Номенклатура");
УсловиеТовар.ОператорСравнения = ОператорСравненияСхемыЗапроса.Равно;

// Дополнительное условие по типу цен (если нужно)
УсловиеТипЦен = Соединение.Условия.Добавить(Тип("СхемаЗапросаУсловие"));
УсловиеТипЦен.ЛевоеВыражение = Новый СхемаЗапросаПоле("Цены.ВидЦены");
УсловиеТипЦен.ПравоеВыражение = Новый СхемаЗапросаПоле("&ВидЦены"); // Параметр
УсловиеТипЦен.ОператорСравнения = ОператорСравненияСхемыЗапроса.Равно;

Шаг 4. Формирование списка выборки (ВЫБРАТЬ)

// Поле: Номенклатура
ПолеНом = Пакет.Поля.Добавить(Тип("СхемаЗапросаПоле"));
ПолеНом.Выражение = Новый СхемаЗапросаПоле("Расход.Номенклатура");
ПолеНом.Псевдоним = "Номенклатура";

// Поле: Количество из документа
ПолеКол = Пакет.Поля.Добавить(Тип("СхемаЗапросаПоле"));
ПолеКол.Выражение = Новый СхемаЗапросаПоле("Расход.Количество");
ПолеКол.Псевдоним = "Количество";

// Поле: Цена из регистра (берем из правой таблицы соединения)
ПолеЦена = Пакет.Поля.Добавить(Тип("СхемаЗапросаПоле"));
ПолеЦена.Выражение = Новый СхемаЗапросаПоле("Цены.Цена");
ПолеЦена.Псевдоним = "ЦенаПродажи";


// Поле: Сумма (вычисляемое)
ПолеСумма = Пакет.Поля.Добавить(Тип("СхемаЗапросаПоле"));
ПолеСумма.Выражение = Новый СхемаЗапросаВыражение("Расход.Количество * Цены.Цена");
ПолеСумма.Псевдоним = "СуммаПродажи";

Шаг 5. Условия отбора (ГДЕ) и группировка

// Условие: Только проведенные документы за период
УсловиеПериод = Пакет.Условия.Добавить(Тип("СхемаЗапросаУсловие"));
УсловиеПериод.ЛевоеВыражение = Новый СхемаЗапросаПоле("Расход.Ссылка.Дата");
УсловиеПериод.ПравоеВыражение = Новый СхемаЗапросаПоле("&НачалоПериода");
УсловиеПериод.ОператорСравнения = ОператорСравненияСхемыЗапроса.БольшеИлиРавно;
// ... добавляем второе условие для конца периода через ЛогическоеИ (структура условий позволяет вложенность)
// Группировка (если нужны итоги)
Пакет.Группировки.Добавить(Новый СхемаЗапросаПоле("Расход;Номенклатура"));

Шаг 6. Получение текста и выполнение

// 1. Генерируем текст
ТекстЗапроса = Схема.ПолучитьТекст;

// 2. Создаем объект Запрос и выполняем
Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;

// Установка параметров (лучше через УстановитьПараметр‚ чем встраивать в текст)
Запрос.УстановитьПараметр("ВидЦены"‚ Справочники.ВидыЦен.НайтиПоНаименованию("Розничная"));
Запрос.УстановитьПараметр("НачалоПериода"‚ НачалоДня(ТекущаяДата ‒ 30));

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

// 3. Обработка результата
Выборка = Результат.Выбрать;
Пока Выборка.Следующий Цикл
 Сообщить(Выборка.Номенклатура + ": " + Выборка.СуммаПродажи);
КонецЦикла;

Конструктор запроса с обработкой результата (Генерация кода)

Платформа 1С предоставляет уникальную возможность: Конструктор запроса с обработкой результата. Он доступен в конфигураторе (меню Администрирование -> Конструктор запроса с обработкой результата или из кода).

Что он делает:

  • Позволяет визуально составить запрос (как обычный конструктор).
  • Автоматически генерирует программный код на встроенном языке‚ который:
    1. Создает объект Запрос.
    2. Заполняет его текст.
    3. Выполняет запрос.

Это идеальный старт для новичка: соберите запрос мышкой‚ нажмите «Получить код»‚ вставьте в модуль и дорабатывайте логику параметров/циклов.


Динамическое формирование текста запроса (Строковый подход)

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

Правила безопасности и чистоты кода:

  1. Никогда не вставляйте значения параметров в текст строкой! Только через Запрос.УстановитьПараметр. Это защита от инъекций и ошибок типов/локализации дат.
  2. Используйте СтроительСтроки для читаемости.
  3. Переносите логику формирования в отдельные функции/методы.

Пример правильного строкового построения:

Функция ПолучитьТекстЗапросаОборотов(ПараметрыОтчета) Экспорт
 
 Строитель = Новый СтроительСтроки;
 
 Строитель.Добавить("ВЫБРАТЬ
 | ХозрасчетныйОбороты.Счет КАК Счет‚
 | ХозрасчетныйОбороты.Субконто1 КАК Субконто1‚
 | СУММА(ХозрасчетныйОбороты.ОборотДт) КАК ОборотДт‚
 | СУММА(ХозрасчетныйОбороты.ОборотКт) КАК ОборотКт
 |ИЗ
 | РегистрБухгалтерии.Хозрасчетный.Обороты(&НачалоПериода‚ &КонецПериода‚ ‚ ) КАК ХозрасчетныйОбороты");
 
 // Динамическое условие
 Если ПараметрыОтчета.ТолькоСДвижениями Тогда
 Строитель.Добавить("
 |ГДЕ
 | ХозрасчетныйОбороты.ОборотДт <> 0
 | ИЛИ ХозрасчетныйОбороты.ОборотКт <> 0");
 КонецЕсли;
 
 Строитель.Добавить("
 |СГРУППИРОВАТЬ ПО
 | ХозрасчетныйОбороты.Счет‚
 | ХозрасчетныйОбороты.Субконто1");
 
 Возврат Строитель;Строка;
 
КонецФункции

Работа с результатом: Программа обработки данных

«Программа запроса» не заканчивается на Выполнить. Критически важна правильная обработка результата.

Основные методы объекта РезультатЗапроса:

Метод Назначение Когда использовать
Выбрать Получить ВыборкаИзРезультатаЗапроса (перебор строк) Построчная обработка‚ заполнение объектов‚ вывод в ТД.
Выгрузить Получить ТаблицаЗначений Дальнейшая аналитика‚ СКД‚ передача в клиентское приложение‚ сериализация.
ВыгрузитьКолонку Получить Массив значений одной колонки Получение списка ID‚ сумм для агрегации без цикла.
Пустой Проверка на пустоту Оптимизация: не перебирать‚ если данных нет.

Паттерн «Выборка по группам» (Иерархический обход):

Если в запросе есть УПОРЯДОЧИТЬ ПО и АВТОУПОРЯДОЧИВАНИЕ‚ можно использовать вложенные выборки:

ВыборкаСчет = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам); // Группировка по Счет
Пока ВыборкаСчет.Следующий Цикл
 // Работа с полями группировки: ВыборкаСчет.Счет
 
 ВыборкаСубконто = ВыборкаСчет.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам); // Вложенная по Субконто1
 Пока ВыборкаСубконто.Следующий Цикл
 // Детальные записи
 ВыборкаДеталь = ВыборкаСубконто.Выбрать; // По записям
 Пока ВыборкаДеталь.Следующий Цикл
 // ...
 КонецЦикла;
 КонецЦикла;
КонецЦикла;

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

Для сложных отчетов (СКД‚ регламентные) часто требуется разбить логику на этапы. В 1С это делается через Пакетные запросы» и «Временные таблицы».

Синтаксис в тексте запроса:

// 1. Помещаем промежуточные данные во временную таблицу
ВЫБРАТЬ
 Номенклатура‚
 СУММА(Количество) КАК Колво
ПОМЕСТИТЬ ВТ_Обороты
ИЗ
 Документ.РасходТовара.Товары КАК Товары
ГДЕ
 Товары.Ссылка.Дата МЕЖДУ &Нач И &Кон
СГРУППИРОВАТЬ ПО
 Номенклатура
;

// 2. Используем временную таблицу в основном запросе
ВЫБРАТЬ
 ВТ_Обороты.Номенклатура‚
 ВТ_Обороты.Колво‚
 Цены.Цена
ИЗ
 ВТ_Обороты КАК ВТ_Обороты
 ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныТоваров.СрезПоследних(&ДатаСреза) КАК Цены
 ПО ВТ_Обороты.Номенклатура = Цены.Номенклатура
;

Программное управление пакетами через СхемуЗапроса:

Схема = Новый СхемаЗапроса;

// Пакет 1: Подготовка ВТ
Пакет1 = Схема.Пакеты.Добавить;
// ... настройка таблиц и полей для ПОМЕСТИТЬ ВТ_Обороты

// Пакет 2: Основной запрос
Пакет2 = Схема.Пакеты.Добавить;
// ... настройка выборки из ВТ_Обороты

Текст = Схема.ПолучитьТекст; // Платформа сама расставит разделители пакетов (;) и ключевые слова

Типичные ошибки и лучшие практики (Best Practices)

⚠️ Ошибка 1: Конкатенация параметров в текст

Плохо: `Запрос.Текст = «ГДЕ Ссылка = ‘» + Строка(Ссылка) + «‘»;`

Хорошо: `Запрос.УстановитьПараметр(«Ссылка»‚ Ссылка);`

Причина: Инъекции‚ формат дат (в БД дата в формате YYYYMMDD)‚ типы данных‚ кэширование планов запросов СУБД.

⚠️ Ошибка 2: Игнорирование индексов и виртуальных таблиц

Всегда используйте СрезПоследних‚ Обороты‚ Балансы вместо ручного JOIN’а таблиц регистров с подзапросами MAX(Период). Оптимизатор СУБД и платформа 1С знают‚ как сделать это быстрее.

⚠️ Ошибка 3: SELECT * (ВЫБРАТЬ *)

Явно перечисляйте поля. Это снижает трафик сети‚ память сервера 1С и делает код устойчивым к изменению метаданных (добавлению реквизитов).

✅ Лучшая практика: Разделение ответственности

  • Функция ПолучитьТекстЗапроса(…) — возвращает только строку текста (чистая логика SQL).
  • Процедура ВыполнитьЗапросИОбработать(…) — создает Запрос‚ ставит параметры‚ вызывает функцию выше‚ выполняет‚ обрабатывает ошибки (Попытка/Исключение)‚ возвращает ТаблицуЗначений или Выборку.

✅ Лучшая практика: Использование ЗапросНастроекКомпоновкиДанных (СКД)

Если запрос нужен для отчета — не пишите «программу запроса» вручную. Используйте Схему компоновки данных (СКД). Она сама формирует запрос на основе настроек пользователя (отборы‚ группировки‚ поля). Ваш код reduziertся к:

КомпоновщикНастроек = Новый КомпоновщикНастроекКомпоновкиДанных;
Настройки = КомпоновщикНастроек.ПолучитьНастройки;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
Макет = КомпоновщикМакета.Выполнить(СхемаКомпоновки‚ Настройки‚ ДанныеРасшифровки);

Отладка и профилирование запросов

Написание программы запроса неполно без проверки производительности.

  1. План запроса (EXPLAIN): В консоли запросов (Конфигуратор -> Администрирование -> Консоль запросов) вставьте текст запроса и нажмите «План запроса». Анализируйте: Table Scan (плохо)‚ Index Seek (хорошо)‚ стоимость операций.
  2. Технологический журнал (ТЖ): Включите регистрацию событий DBPOSTGRS‚ DBMSSQL‚ SDBL с фильтром по длительности (> 1000мс). Найдите «тяжелые» запросы в продакшене.
  3. Консоль производительности (Performance Monitor): Встроенная панель в тонком/толстом клиенте (Ctrl+Alt+Delete в конфигураторе или меню «Администрирование» -> «Производительность»).

Умение составить программу запроса в 1С:Предприятие 8.3 — это переход от уровня «кодера» к уровню «архитектора данных».

Ключевые выводы:

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

Грамотная программа запроса — это не просто текст на языке SQL-диалекта 1С‚ это управляемая‚ читаемая‚ безопасная и производительная логика доступа к данным вашего приложения.


Статья подготовлена на основе актуальной документации платформы 1С:Предприятие 8.3 и практики разработки высоконагруженных систем. Примеры кода носят демонстрационный характер и могут требовать адаптации под конкретную конфигурацию (УТ‚ ERP‚ КА‚ самописная).