Как сопоставить параметры критерия отбора с результатом запроса и суммировать подчиненные документы

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

При разработке отчетов и обработок в 1С часто возникает задача получения данных не только по основным объектам (например, Заказам), но и по всем связанным с ними подчиненным документам. Стандартный механизм Критерии отбора отлично работает в интерфейсе, но при попытке использовать его в сложных запросах программисты сталкиваются с ограничениями платформы. Рассмотрим, как правильно объединить данные о заказах и их подчиненных приложениях в одном запросе, чтобы корректно рассчитать итоговые суммы по замерщикам или менеджерам.

Проблема использования критериев отбора в запросах

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

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

Решение через прямое соединение таблиц

Чтобы избежать выполнения запроса в цикле (что создает колоссальную нагрузку на сервер СУБД), нам следует перейти к использованию соединений физических таблиц документов. Разберем логику построения такого запроса на примере. Если нам заранее известно, что итоговую сумму заказа могут менять только документы типа ПриложениеКЗаказу, мы можем напрямую соединить таблицу Документ.Заказ с таблицей Документ.ПриложениеКЗаказу по полю ДокОснование.

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


ВЫБРАТЬ
    Заказ.Ссылка КАК Документ,
    Заказ.Дата КАК Дата,
    Заказ.Замерщик КАК Замерщик,
    ВЫБОР
        КОГДА НЕ ПриложениеКЗаказу.Ссылка ЕСТЬ NULL
            ТОГДА Заказ.ДогСумма + ПриложениеКЗаказу.Сумма_Итог
        ИНАЧЕ Заказ.ДогСумма
    КОНЕЦ КАК Сумма,
    Заказ.Автор КАК Автор,
    ПриложениеКЗаказу.Ссылка КАК СсылкаПриложения
ИЗ
    Документ.Заказ КАК Заказ
        ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПриложениеКЗаказу КАК ПриложениеКЗаказу
        ПО Заказ.Ссылка = ПриложениеКЗаказу.ДокОснование
ГДЕ
    Заказ.Проведен = ИСТИНА
    И Заказ.Дата МЕЖДУ &НачалоПериода И &КонецПериода
    И Заказ.Направление = &Направление
УПОРЯДОЧИТЬ ПО
    Дата
ИТОГИ
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Документ),
    СУММА(Сумма)
ПО
    Замерщик

В этом запросе мы используем ЛЕВОЕ СОЕДИНЕНИЕ, чтобы не потерять заказы, у которых нет приложений. Поле Сумма вычисляется динамически с помощью конструкции ВЫБОР. Если ссылка на приложение найдена, мы суммируем значения, если нет — берем только сумму заказа.

Ловушка дублирования строк и искажения итогов

Проанализируем важный нюанс, который часто упускают из виду. Если у одного заказа будет два и более подчиненных приложения, то использование простого ЛЕВОЕ СОЕДИНЕНИЕ приведет к "размножению" строк основного заказа в результате запроса. Например, если Заказ №1 на сумму 1000 руб. имеет два Приложения по 500 руб. каждое, то в выборке появятся две строки. Это приведет к тому, что при расчете общих итогов по замерщику сумма самого Заказа №1 будет ошибочно просуммирована дважды.

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


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

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    Заказ.Ссылка КАК Документ,
    Заказ.Замерщик КАК Замерщик,
    Заказ.ДогСумма + ЕСТЬNULL(ВТ_СуммыПриложений.СуммаПриложений, 0) КАК ОбщаяСумма
ИЗ
    Документ.Заказ КАК Заказ
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_СуммыПриложений КАК ВТ_СуммыПриложений
        ПО Заказ.Ссылка = ВТ_СуммыПриложений.ДокОснование
ГДЕ
    Заказ.Проведен = ИСТИНА
    И Заказ.Дата МЕЖДУ &НачалоПериода И &КонецПериода
ИТОГИ
    СУММА(ОбщаяСумма)
ПО
    Замерщик

Используя такой подход, мы гарантируем, что каждая ссылка на Заказ встретится в итоговой выборке ровно один раз, а все суммы приложений будут корректно предварительно просуммированы. Функция ЕСТЬNULL здесь критически важна, чтобы при отсутствии приложений сумма не превратилась в NULL при сложении.

Оптимизация и производительность

Разберем несколько советов, которые помогут вашему запросу работать быстрее, особенно в нетиповых конфигурациях без использования БСП:

  1. Индексация реквизитов: Убедитесь, что реквизит ДокОснование в документе ПриложениеКЗаказу проиндексирован. В конфигураторе в свойствах реквизита должно стоять значение Индексировать. Это позволит СУБД мгновенно находить связи, не перебирая всю таблицу приложений целиком.
  2. Работа с правами доступа: Если вы используете слово РАЗРЕШЕННЫЕ, помните, что система проверяет права на все таблицы в соединении. Если у пользователя нет прав на просмотр "Приложений к заказу", их суммы просто не попадут в итоговый отчет, даже если заказы ему доступны.
  3. Ограничение выборки: Старайтесь ограничивать выборку подчиненных документов по периоду или другим критериям еще на этапе формирования временной таблицы, чтобы не обрабатывать лишние данные за прошлые годы.

Таким образом, мы выяснили, что замена виртуальных таблиц Критериев отбора на прямые соединения с предварительной группировкой — это наиболее эффективный способ получения связанных данных в 1С. Это избавляет от тяжелых циклов в коде и обеспечивает математическую точность итогов в отчетах.

← На главную