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

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

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

Почему не стоит использовать запросы внутри цикла?

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

Разбор архитектуры связей

Связи между документами в типовых решениях 1С почти всегда реализованы через поля ссылочного типа, чаще всего это ДокументОснование. Прежде чем писать запрос, мы должны убедиться, какие именно реквизиты участвуют в связке. Например, ЗаявкаНаРасходованиеДенежныхСредств ссылается на АвансовыйОтчет, а СписаниеБезналичныхДенежныхСредств — на Заявку или сам АвансовыйОтчет.

Решение задачи с помощью левых соединений

Самый эффективный способ — использовать ЛЕВОЕ СОЕДИНЕНИЕ (LEFT JOIN). Это позволит нам получить все авансовые отчеты сразу и «приклеить» к ним информацию о связанных документах, если таковые существуют. Если связи нет, значение в реквизите будет NULL.

Рассмотрим, как выстроить такой запрос по шагам:

  1. Выбираем основной документ — АвансовыйОтчет.
  2. Соединяем его с таблицей ЗаявкаНаРасходованиеДенежныхСредств по полю ДокументОснование.
  3. Соединяем результат с таблицей СписаниеБезналичныхДенежныхСредств.

Пример реализации запроса:


ВЫБРАТЬ
    АвансовыйОтчет.Ссылка КАК АвансовыйОтчет,
    Заявка.Ссылка КАК Заявка,
    Списание.Ссылка КАК Списание
ИЗ
    Документ.АвансовыйОтчет КАК АвансовыйОтчет
ЛЕВОЕ СОЕДИНЕНИЕ 
    Документ.ЗаявкаНаРасходованиеДенежныхСредств КАК Заявка
ПО 
    Заявка.ДокументОснование = АвансовыйОтчет.Ссылка
ЛЕВОЕ СОЕДИНЕНИЕ 
    Документ.СписаниеБезналичныхДенежныхСредств КАК Списание
ПО 
    Списание.ДокументОснование = Заявка.Ссылка
ГДЕ
    АвансовыйОтчет.Дата МЕЖДУ &НачДата И &КонДата

Как классифицировать результаты

Теперь, когда у нас есть все данные в одном наборе, мы можем легко разделить их на группы с помощью инструкции ВЫБОР КОГДА. Это позволит нам мгновенно понять статус каждого авансового отчета:


ВЫБРАТЬ
    АвансовыйОтчет.Ссылка,
    ВЫБОР
        КОГДА Заявка.Ссылка ЕСТЬ NULL ТОГДА "Нет связанных"
        КОГДА Списание.Ссылка ЕСТЬ NULL ТОГДА "Только заявка"
        ИНАЧЕ "Заявка и списание"
    КОНЕЦ КАК Статус
ИЗ 
    Документ.АвансовыйОтчет КАК АвансовыйОтчет
ЛЕВОЕ СОЕДИНЕНИЕ 
    Документ.ЗаявкаНаРасходованиеДенежныхСредств КАК Заявка
ПО 
    Заявка.ДокументОснование = АвансовыйОтчет.Ссылка
ЛЕВОЕ СОЕДИНЕНИЕ 
    Документ.СписаниеБезналичныхДенежныхСредств КАК Списание
ПО 
    Списание.ДокументОснование = Заявка.Ссылка

Важные рекомендации при работе с типами

Поскольку реквизиты ДокументОснование часто имеют составной тип, при написании запросов не забывайте про операторы ВЫРАЗИТЬ и ССЫЛКА. Это предотвращает ошибки при соединении таблиц, когда в реквизите могут находиться документы разных типов.

Если вам нужно проверить проведение документа, просто добавьте условие в секцию ГДЕ или в условие соединения:


ЛЕВОЕ СОЕДИНЕНИЕ 
    Документ.СписаниеБезналичныхДенежныхСредств КАК Списание
ПО 
    Списание.ДокументОснование = Заявка.Ссылка
    И Списание.Проведен = ИСТИНА

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

← На главную