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

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

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

Ограничения использования критерия отбора

В типовых конфигурациях (включая УПП, КА, УТ 10.3) существует предопределенный объект метаданных КритерийОтбора.ДокументыПоКонтрагенту. В тексте запроса к нему можно обратиться напрямую:


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

Однако при попытке связать этот запрос со списком контрагентов разработчики сталкиваются с ограничением платформы: параметр виртуальной таблицы критерия отбора принимает только одиночную ссылку. Передать массив или результат вложенного запроса в &Контрагент невозможно.

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

  1. Создаем первый набор данных — список контрагентов.
  2. Создаем второй набор данных — запрос к критерию отбора с параметром.
  3. На вкладке «Связи наборов данных» связываем источник и приемник по полю Ссылка, передавая его в параметр &Контрагент. В этом случае платформа берет оптимизацию выполнения запросов на себя.

Особенности структуры данных: учет договоров и табличных частей

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

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

Программная генерация сводного запроса по метаданным

Чтобы не писать вручную запросы с десятками объединений (ОБЪЕДИНИТЬ ВСЕ) и не пропускать добавленные нетиповые документы, сформируем текст запроса динамически на основе коллекции Метаданные.Документы.

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


ТекстЗапроса = "";
Разделитель = "";

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

КонецЦикла;

Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("СписокКонтрагентов", МассивКонтрагентов);
Запрос.УстановитьПараметр("ДатаНачала", НачалоПериода);
Запрос.УстановитьПараметр("ДатаОкончания", КонецПериода);

Результат = Запрос.Выполнить().Выгрузить();

Использование метода «НайтиПоСсылкам»

Если требуется определить, используется ли контрагент в базе вообще (для последующего удаления неиспользуемых элементов), наиболее быстрым способом является глобальный метод НайтиПоСсылкам.

Рассмотрим, как его применить:

  1. Передаем в метод массив проверяемых контрагентов. Метод обращается к внутренним системным таблицам ссылочной целостности СУБД и мгновенно возвращает таблицу со всеми найденными ссылками.
  2. Поскольку метод НайтиПоСсылкам не фильтрует по признаку проведения и дате, передаем полученную колонку Данные в запрос как параметр или помещаем во временную таблицу.
  3. В запросе связываем данные с таблицами документов и накладываем условие Проведен = ИСТИНА.

Проверка по регистрам учета

Если перед нами стоит задача проверить не просто наличие документов, а факт реального отражения операций в учете, проверку можно свести к анализу регистров:

  1. Регистр бухгалтерии: В конфигурациях с регламентированным учетом обращение к виртуальной таблице РегистрБухгалтерии.Хозрасчетный.Обороты с отбором по субконто «Контрагенты» позволяет одним коротким запросом выявить все проводки за период без сканирования таблиц отдельных документов.
  2. Регистры взаиморасчетов и накопления: В управленческих базах проверяются регистры «Взаиморасчеты с контрагентами» или «Заказы покупателей». Это существенно снижает время выполнения выборки по сравнению с прямым перебором документов.

Оптимизация при больших объемах данных

При выполнении выборок по сотням тысяч документов и большому количеству контрагентов придерживаемся следующих правил:

  1. Индексация временных таблиц: Если список контрагентов передается во временную таблицу, всегда добавляем директиву ИНДЕКСИРОВАТЬ ПО для ключевых полей.
  2. Использование признака быстрого выхода: Если нужно выяснить только сам факт активности контрагента (без подсчета точного числа документов), в запросах достаточно выбирать ВЫБРАТЬ РАЗЛИЧНЫЕ или использовать проверку наличия хотя бы одной записи.
  3. Группировка запросов: Если объединяется слишком много таблиц документов, оптимизатор СУБД может тратить дополнительное время на построение плана выполнения. В таком случае целесообразно выполнять пакет запросов блоками по 10–15 документов, помещая результаты в промежуточную таблицу.
← На главную