Как правильно реализовать выборку из оборотного регистра накопления с фильтрацией по условиям

Программист 1С v8.3 (Обычные формы) Управленческий учет Промышленность, строительство и АПК
← На главную

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

Выбор таблицы для запроса: Физическая или Виртуальная

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

Виртуальная таблица Обороты предоставляет уже агрегированные данные. Если мы обратимся к физической таблице, нам придется самостоятельно группировать записи по измерениям и суммировать ресурсы, что существенно замедлит выполнение кода и усложнит текст запроса. Использование виртуальной таблицы позволяет переложить расчет итогов на уровень СУБД, что работает значительно быстрее.

Наложение условий на виртуальную таблицу

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

  1. Параметры виртуальной таблицы (Условие): Сюда следует помещать фильтры по измерениям регистра. В нашем случае это фильтр по номенклатуре (материалу), у которой основной поставщик совпадает с контрагентом из документа. Если мы накладываем условие здесь, платформа оптимизирует запрос так, чтобы СУБД выбирала только нужные записи еще на этапе формирования временных итогов.
  2. Секция ГДЕ: Сюда выносятся условия, которые невозможно вычислить до момента получения итогов. Сравнение двух ресурсов (например, КЗаказуПоставщика > ЗаказаноПоставщику) выполняется именно здесь, так как эти значения становятся известны только после того, как система просуммирует все обороты по конкретной аналитике.

Практический пример реализации запроса

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


Процедура КоманднаяПанельТоварыЗаполнитьПоПотребностямЗаказа(Кнопка)
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |    ПотребностиПроизводстваОбороты.Машина КАК Машина,
        |    ПотребностиПроизводстваОбороты.Материал КАК Номенклатура,
        |    ПотребностиПроизводстваОбороты.Материал.ЕдиницаДляОтчетов КАК ЕдиницаИзмерения,
        |    ПотребностиПроизводстваОбороты.ЗаказаноПоставщикуОборот КАК Количество
        |ИЗ
        |    РегистрНакопления.ПотребностиПроизводства.Обороты(
        |            &НачалоПериода, 
        |            &КонецПериода, 
        |            , 
        |            Материал.ОсновнойПоставщик = &Контрагент) КАК ПотребностиПроизводстваОбороты
        |ГДЕ
        |    ПотребностиПроизводстваОбороты.КЗаказуПоставщикаОборот > ПотребностиПроизводстваОбороты.ЗаказаноПоставщикуОборот";

    Запрос.УстановитьПараметр("Контрагент", Контрагент); // Контрагент из шапки документа
    Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(Дата)); // Опционально: ограничение периода
    Запрос.УстановитьПараметр("КонецПериода", КонецДня(Дата));

    // Выгружаем результат запроса напрямую в табличную часть
    Товары.Загрузить(Запрос.Выполнить().Выгрузить());
КонецПроцедуры

Важные нюансы и оптимизация

Разберем по шагам ключевые моменты представленного кода и добавим рекомендации по его улучшению:

1. Обращение через точку (Материал.ОсновнойПоставщик): В параметрах виртуальной таблицы мы используем обращение к реквизиту справочника через точку. Это допустимо, но стоит помнить, что в SQL это превратится в LEFT JOIN с таблицей справочника номенклатуры. Для высоконагруженных систем рекомендуется сначала отобрать список номенклатуры конкретного поставщика во временную таблицу, а затем передать этот список в параметры оборотов.

2. Использование ЕСТЬNULL: Если существует вероятность, что какой-то из ресурсов в регистре может быть не заполнен (хотя для числовых ресурсов это редкость при правильном ведении учета), в секции ГДЕ и ВЫБРАТЬ лучше использовать функцию ЕСТЬNULL(Значение, 0). Это предотвратит ошибки при сравнении чисел с неопределенным значением.

3. Метод Загрузить(): Команда Товары.Загрузить() полностью очищает существующие строки в табличной части и заменяет их новыми. Если ваша логика предполагает добавление строк к уже существующим, используйте обход выборки в цикле:


Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    НоваяСтрока = Товары.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка);
КонецЦикла;

4. Периоды виртуальной таблицы: Никогда не оставляйте первые два параметра таблицы Обороты пустыми в реальных задачах. Без указания &НачалоПериода и &КонецПериода система будет анализировать весь объем данных регистра за все годы ведения учета, что приведет к критическому падению производительности по мере роста базы.

Заключение

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

← На главную