Как в запросе 1С разделить приход по конкретному документу и остальным операциям в разные колонки?

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

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

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

Вариант 1: Использование конструкции ВЫБОР в полях запроса

Самый прямой и часто используемый способ — это применение конструкции ВЫБОР непосредственно в списке полей выборки. Этот метод позволяет за один проход по данным распределить значения по нужным колонкам. Разберем логику построения такого запроса.

Для того чтобы получить две разные колонки, нам необходимо создать два отдельных выражения ВЫБОР. В первом мы будем проверять соответствие регистратора нужному типу, а во втором — отсекать его. Важно не забывать про секцию ИНАЧЕ, чтобы избежать появления значений NULL, которые могут привести к ошибкам при дальнейших арифметических операциях.

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


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

В данном примере мы используем оператор ССЫЛКА, который позволяет системе быстро определить тип документа. Проанализируем ситуацию с оператором НЕ. Среди разработчиков существует мнение, что использования НЕ (NOT) стоит избегать. В контексте секции ГДЕ это действительно критично, так как может помешать использованию индексов СУБД. Однако в секции ВЫБОР нагрузка ложится в основном на процессор при вычислении результата для каждой строки, что в большинстве случаев не является "узким местом".

Вариант 2: Использование ОБЪЕДИНИТЬ ВСЕ

Существует альтернативный подход, который заключается в разделении запроса на два независимых блока, результаты которых затем объединяются. Это может быть полезно, если условия фильтрации очень сложные или если вы хотите максимально упростить чтение каждой части запроса.

Разберем по шагам, как это работает:

  1. В первом запросе мы выбираем только данные по ПоступлениеТоваровУслуг, а вторую колонку (для прочих приходов) заполняем нулем.
  2. Во втором запросе мы выбираем все остальные документы, а первую колонку заполняем нулем.
  3. Используем оператор ОБЪЕДИНИТЬ ВСЕ для слияния результатов.

ВЫБРАТЬ
    ТоварыНаСкладахОстаткиИОбороты.Номенклатура,
    ТоварыНаСкладахОстаткиИОбороты.КоличествоПриход КАК КоличествоПриходПоступление,
    0 КАК КоличествоПриходПрочее
ИЗ
    РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(&ДатаНачала, &ДатаКонца, Регистратор, , Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг) КАК ТоварыНаСкладахОстаткиИОбороты

ОБЪЕДИНИТЬ ВСЕ

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

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

Анализ производительности и работа с виртуальными таблицами

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

Чтобы оптимизировать такой запрос, придерживайтесь следующих правил:

Оптимальный "сводный" запрос

Наиболее профессиональным подходом считается совмещение фильтрации и группировки. Если нам нужно получить итоговые цифры за период в разрезе номенклатуры, лучше всего использовать конструкцию СУММА(ВЫБОР...). Это позволяет "развернуть" строки в колонки за один проход по таблице.

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


ВЫБРАТЬ
    Т.Номенклатура КАК Номенклатура,
    СУММА(ВЫБОР
            КОГДА Т.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг
                ТОГДА Т.КоличествоПриход
            ИНАЧЕ 0
        КОНЕЦ) КАК ПриходПоступление,
    СУММА(ВЫБОР
            КОГДА НЕ Т.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг
                ТОГДА Т.КоличествоПриход
            ИНАЧЕ 0
        КОНЕЦ) КАК ПриходПрочее
ИЗ
    РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(&ДатаНачала, &ДатаКонца, Регистратор, , ) КАК Т
СГРУППИРОВАТЬ ПО
    Т.Номенклатура

Выясним причину, почему этот вариант хорош: он лаконичен, легко читается и эффективно обрабатывается оптимизатором СУБД. Мы получаем готовую таблицу, где для каждой номенклатуры четко разделены потоки поступлений.

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

← На главную