При работе с виртуальными таблицами регистров накопления (такими как Обороты или ОстаткиИОбороты) разработчики часто сталкиваются с необходимостью динамически менять детализацию данных. Например, в зависимости от выбора пользователя в отчете, данные должны группироваться по дням, месяцам или годам. Однако попытка передать периодичность через стандартный параметр, например, &Периодичность, приводит к ошибке синтаксиса в конструкторе запросов.
В этой статье мы подробно разберем, почему так происходит, и рассмотрим все существующие способы решения этой задачи, от простых "костылей" до современных объектных методов платформы 1С:Предприятие 8.
Разберем ситуацию с точки зрения архитектуры СУБД. Когда мы пишем запрос к виртуальной таблице РегистрНакопления.Продажи.Обороты(,, День,), платформа 1С не просто подставляет значение в SQL-запрос. Она анализирует слово День и на его основе выбирает, к какой именно физической таблице итогов обратиться и какие группировки (GROUP BY) использовать в результирующем SQL-коде.
Параметр запроса (через &) предназначен для передачи значений полей (дат, ссылок, чисел), но он не может менять саму структуру запроса. Поскольку выбор периодичности принципиально меняет структуру генерируемого SQL, платформа требует, чтобы это значение было жестко задано как литерал на этапе компиляции запроса.
Это самый распространенный и быстрый в реализации метод. Мы создаем текст запроса, в котором на месте периодичности вставляем специальный маркер-метку, а затем программно заменяем его на нужное ключевое слово.
Рассмотрим по шагам, как это реализовать:
СтрЗаменить для модификации текста перед выполнением запроса.Пример программного кода:
// 1. Формируем шаблон текста запроса
ТекстЗапроса =
"ВЫБРАТЬ
| ПродажиОбороты.Период КАК Период,
| ПродажиОбороты.СуммаОборот КАК Сумма
|ИЗ
| РегистрНакопления.Продажи.Обороты(&Начало, &Конец, &МояПериодичность, ) КАК ПродажиОбороты";
// 2. Определяем значение (например, из настроек пользователя или переключателя)
ЗначениеПериодичности = "Месяц"; // Могло прийти как параметр функции
// 3. Подставляем реальное значение вместо маркера
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&МояПериодичность", ЗначениеПериодичности);
// 4. Выполняем запрос
Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("Начало", НачалоПериода);
Запрос.УстановитьПараметр("Конец", КонецПериода);
Результат = Запрос.Выполнить();
Важный нюанс: Обратите внимание, что в самом запросе маркер &МояПериодичность не является параметром в понимании 1С (мы не вызываем УстановитьПараметр для него). Мы работаем с ним просто как с фрагментом строки.
Если вы разрабатываете отчет, то использование СКД — это самый правильный и "штатный" путь. В СКД механизм работы с виртуальными таблицами реализован гибче, чем в обычном запросе.
Проанализируем, как настроить управление периодичностью в СКД:
{(&Периодичность)}. Это даст понять СКД, что параметр является частью настроек компоновки.Периодичность.Платформа использует числовые индексы для определения типа периода в СКД. Рассмотрим соответствие чисел и типов:
Таким образом, передавая в параметр СКД число 10, вы получите данные с группировкой по месяцам. Это работает автоматически, так как компоновщик сам перестраивает текст запроса перед отправкой в СУБД.
Если вы хотите избежать "ручной склейки строк" и работать в чисто объектном стиле, воспользуйтесь объектом СхемаЗапроса. Этот метод позволяет программно разбирать и собирать запрос, обращаясь к его частям как к свойствам объектов.
Разберем пример изменения периодичности через СхемаЗапроса:
// Создаем объект схемы и загружаем в него исходный текст
Схема = Новый СхемаЗапроса;
Схема.УстановитьТекстЗапроса("ВЫБРАТЬ * ИЗ РегистрНакопления.Продажи.Обороты(,, День,) КАК Продажи");
// Получаем первый оператор выбора и таблицу
ОператорВыбора = Схема.ПакетЗапросов[0].Операторы[0];
ТаблицаРегистра = ОператорВыбора.Источники[0].Источник;
// Устанавливаем новую периодичность через свойство параметров виртуальной таблицы
// 10 соответствует значению "Месяц" в перечислении параметров
ТаблицаРегистра.Параметры[2].Выражение = Новый ВыражениеСхемыЗапроса("Месяц");
// Получаем обратно модифицированный текст
ТекстЗапроса = Схема.ПолучитьТекстЗапроса();
Использование СхемаЗапроса гарантирует, что вы не допустите опечатку в синтаксисе, которую легко совершить при использовании СтрЗаменить.
Выясним важную деталь: если ваша задача требует периодического переключения на уровень Регистратор, будьте осторожны. Периодичность Регистратор требует обязательного наличия соответствующих полей в секции ВЫБРАТЬ вашего запроса.
Если в вашем универсальном запросе выбрано только поле СуммаОборот, и вы программно подставите периодичность Регистратор, запрос может отработать некорректно или не вернуть данные в нужной детализации. Всегда проверяйте, чтобы набор выбираемых полей соответствовал выбранному уровню детализации.
Проанализируем ситуацию с нагрузкой на сервер. Выбор периодичности напрямую влияет на скорость выполнения:
Совет: Если вы строите динамический отчет, всегда старайтесь ограничивать период выборки (НачалоПериода и КонецПериода), особенно если пользователь выбирает высокую детализацию (День или Секунда).
Мы рассмотрели три основных подхода к решению проблемы. Для простых обработок идеально подойдет метод СтрЗаменить. Для сложных профессиональных отчетов лучше использовать механизмы СКД. А если требуется программная генерация сложных запросов в коде модулей — объект СхемаЗапроса станет самым надежным инструментом. Выбирайте метод исходя из архитектуры вашей задачи, помня о производительности системы.