Как указать параметр Начало периода выборкой из временной таблицы в 1С

Программист 1С v8.3 (Управляемые формы) Бухгалтерский учет IT и автоматизация бизнеса
← На главную

При разработке сложных отчетов или обработок на платформе 1С:Предприятие программисты часто сталкиваются с необходимостью сделать запрос максимально динамическим. Типичная ситуация: мы сначала вычисляем некую дату (например, дату первого документа в цепочке или минимальную дату оплаты) и помещаем ее во временную таблицу. Казалось бы, логично далее использовать эту дату в качестве параметра НачалоПериода для виртуальной таблицы остатков или оборотов. Однако при попытке вставить подзапрос в круглые скобки виртуальной таблицы конструктор запроса выдает ошибку, а система отказывается выполнять такой код.

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

Почему нельзя использовать подзапрос в параметрах виртуальной таблицы

Прежде чем переходить к решениям, проанализируем причину возникновения проблемы. В языке запросов 1С параметры виртуальных таблиц (такие как Остатки, Обороты, ОстаткиИОбороты) должны быть определены на момент подготовки плана выполнения запроса. Платформа 1С проектировалась таким образом, что параметры внутри круглых скобок () транслируются в SQL-запрос как константы или переменные сервера приложений.

Использование конструкции (ВЫБРАТЬ МИНИМУМ(Дата) ИЗ ВТ) внутри параметров виртуальной таблицы нарушает этот принцип. Система не может заранее знать, какое значение вернет подзапрос, чтобы оптимально выбрать таблицы итогов (агрегаты), которые будут задействованы. Таким образом, это жесткое ограничение платформы, которое невозможно обойти простым изменением синтаксиса внутри одного текста запроса.

Способ 1. Программный метод: использование двух запросов и менеджера временных таблиц

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

Рассмотрим алгоритм действий:

  1. Создаем МенеджерВременныхТаблиц.
  2. Выполняем первый запрос, который находит нужную дату и помещает ее во временную таблицу (ВТ).
  3. Выполняем промежуточный легкий запрос к этой ВТ, чтобы получить значение даты в переменную 1С.
  4. Передаем полученную переменную как обычный параметр во второй запрос, используя тот же менеджер временных таблиц.

Посмотрим на пример кода:


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

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

// 2. Извлекаем значение даты из ВТ
Запрос2 = Новый Запрос;
Запрос2.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос2.Текст = "ВЫБРАТЬ МинДата ИЗ ВТ_ГраницаПериода";
Результат = Запрос2.Выполнить().Выгрузить();

Если Результат.Количество() > 0 Тогда
    НужнаяДата = Результат[0].МинДата;
Иначе
    НужнаяДата = '00010101';
КонецЕсли;

// 3. Выполняем основной запрос с передачей параметра
Запрос3 = Новый Запрос;
Запрос3.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос3.Текст = 
    "ВЫБРАТЬ
    |   ХозрасчетныйОстатки.СуммаОстаток
    |ИЗ
    |   РегистрБухгалтерии.Хозрасчетный.Остатки(&Период, Счет = &Счет, , ) КАК ХозрасчетныйОстатки";

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

Этот метод гарантирует максимальную производительность, так как СУБД получает четкое значение периода и сразу обращается к нужной таблице итогов.

Способ 2. Использование Системы компоновки данных (СКД)

Если задача решается в рамках построения отчета, то Система компоновки данных предоставляет более элегантный механизм — Связи наборов данных. В СКД можно создать два отдельных набора данных "Запрос".

Проанализируем этот механизм:

Разберем настройку связи по шагам:

  1. Перейдем на закладку "Связи наборов данных".
  2. Укажем источником связи Набор1, а приемником Набор2.
  3. В колонке "Параметры" для связи выберем соответствующий параметр НачалоПериода (или другой нужный).
  4. В колонке "Условие связи" сопоставим поле с датой из Набор1.

В этом случае СКД при выполнении компоновки сама сначала вычислит значение из первого набора и "подставит" его в параметр второго набора на уровне генерации SQL-запроса. Для пользователя и разработчика это выглядит как автоматическая передача данных из одной выборки в параметры другой.

Способ 3. Метод "Широкого фильтра" в секции ГДЕ (Ограничения и риски)

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


ВЫБРАТЬ
    Продажи.Номенклатура,
    Продажи.СуммаОборот
ИЗ
    РегистрНакопления.Продажи.Обороты(, &ДатаКон, , ) КАК Продажи
ГДЕ
    Продажи.Период >= (ВЫБРАТЬ МИНИМУМ(ДатаНачала) ИЗ ВТ_События)

Внимание: проанализируем критические недостатки этого метода!

Когда вы оставляете поле Начало периода пустым, система 1С по умолчанию берет данные с самой ранней даты, доступной в регистре (0001-01-01). СУБД будет вынуждена прочитать и просуммировать все записи регистра с момента его создания до &ДатаКон. Секция ГДЕ применится уже после того, как виртуальная таблица будет сформирована в памяти. Если ваш регистр содержит миллионы записей за 10 лет, а вам нужен оборот за последние 2 дня, такой запрос может просто "повесить" сервер или выполняться крайне долго.

Этот метод допустим только для небольших справочных регистров или в исключительных случаях для регистров оборотов, если вы точно уверены, что объем данных невелик. Для регистров накопления с остатками или регистров бухгалтерии этот метод категорически не рекомендуется.

Важные выводы и рекомендации

Выяснив причину ограничения и рассмотрев варианты решения, можно подвести итоги:

  1. Прямая вставка подзапроса в параметры невозможна из-за архитектуры трансляции запросов 1С в SQL.
  2. Для обычных обработок и процедур используйте разделение запроса на этапы с извлечением даты в переменную через МенеджерВременныхТаблиц.
  3. Для отчетов используйте связи параметров наборов данных в СКД. Это наиболее технологичный путь, который сохраняет декларативный стиль разработки.
  4. Избегайте фильтрации периодов в секции ГДЕ без указания параметров в скобках виртуальной таблицы, чтобы не допустить деградации производительности системы.

Применяя эти подходы, вы сможете создавать гибкие и производительные запросы, обходя синтаксические ограничения платформы 1С:Предприятие без потери качества кода.

← На главную