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