При разработке в среде 1С:Предприятие часто возникает задача программного поиска связей между объектами. Одной из наиболее типичных является поиск всех подчиненных документов для конкретного основания. Ситуация усложняется, когда необходимо не просто вывести список, но и проанализировать его на наличие дублей. В этой статье мы подробно разберем, почему стандартные механизмы иерархии не подходят для документов, как правильно использовать критерии отбора и как строить запросы для поиска повторяющихся записей.
Начинающие разработчики часто пытаются применить конструкцию В ИЕРАРХИИ к документам, проводя аналогию со справочниками. Давайте проанализируем, почему это ошибочный путь. В платформе 1С оператор В ИЕРАРХИИ (IN HIERARCHY) предназначен для работы с объектами, имеющими встроенную иерархическую структуру «группа — элемент» или «элемент — элемент» (родительская связь). У документов такое свойство отсутствует на уровне ядра платформы.
Важно понимать: связь между документами в 1С обычно строится через реквизит типа «Ссылка», который разработчики часто называют ДокументОснование. Это логическая связь, а не физическая иерархия таблиц. Поэтому попытка выполнить запрос ГДЕ Ссылка В ИЕРАРХИИ (&ДокументСсылка) не вернет подчиненные документы, так как платформа не увидит в них наследников указанного объекта.
Самым эффективным и быстрым способом получения списка подчиненных документов является использование объекта метаданных Критерий отбора. Рассмотрим, как это работает. Если в вашей конфигурации настроен критерий отбора (например, с именем СвязанныеДокументы), платформа автоматически поддерживает индекс связей, что делает поиск практически мгновенным.
Для обращения к этим данным в языке запросов используется специальная виртуальная таблица. Разберем пример синтаксиса:
ВЫБРАТЬ
СвязанныеДокументы.Ссылка КАК Документ
ИЗ
КритерийОтбора.СвязанныеДокументы(&Основание) КАК СвязанныеДокументы
В данном случае в качестве параметра &Основание мы передаем ссылку на родительский документ. Платформа сама проанализирует все объекты, указанные в составе критерия отбора, и вернет те, которые ссылаются на наше &Основание.
Если же вам необходимо получить данные программно без использования текста запроса (например, для вывода в список), можно использовать метод:
СписокДокументов = КритерииОтбора.СвязанныеДокументы.Найти(ИскомыйДокумент);
Если вы работаете с полностью самописной конфигурацией, где критерии отбора не настроены, задача усложняется. В этом случае у нас есть два пути. Проанализируем каждый из них.
Способ 1: Прямой запрос к известным таблицам. Если мы точно знаем, какие типы документов могут быть подчинены, мы используем ОБЪЕДИНИТЬ ВСЕ:
ВЫБРАТЬ Ссылка ИЗ Документ.РеализацияТоваровУслуг ГДЕ ДокументОснование = &Основание
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ Ссылка ИЗ Документ.СчетФактураВыданный ГДЕ ДокументОснование = &Основание
Способ 2: Универсальный поиск через метаданные. Если видов документов много, мы можем программно перебрать метаданные и построить динамический запрос. Нам нужно проверить каждый документ на наличие реквизита, тип которого совпадает с типом нашего документа-основания. Обратите внимание, что реквизит может находиться как в шапке, так и в табличной части.
Перейдем ко второй части вопроса — поиску дублей среди найденных документов. Часто разработчики совершают ошибку, пытаясь использовать условие СУММА(1) > 1 или КОЛИЧЕСТВО(*) > 1 в секции ГДЕ. Выясним причину, почему это не работает.
В языке SQL и языке запросов 1С секция ГДЕ (WHERE) фильтрует строки до того, как будет выполнена группировка и расчет агрегатных функций. Для фильтрации уже сгруппированных данных (результатов функций СУММА, КОЛИЧЕСТВО и т.д.) предназначена специальная секция ИМЕЮЩИЕ (HAVING).
Рассмотрим пошагово алгоритм поиска дублей по номеру и дате в таблице документов:
КОЛИЧЕСТВО(Ссылка) или просто КОЛИЧЕСТВО(*).СГРУППИРОВАТЬ ПО для всех выбранных полей, кроме агрегатных.ИМЕЮЩИЕ для отбора записей, где количество больше единицы.Посмотрим на пример готового запроса для поиска дублей в документах продажи:
ВЫБРАТЬ
Продажа.Номер КАК Номер,
Продажа.Дата КАК Дата,
КОЛИЧЕСТВО(Продажа.Ссылка) КАК КоличествоПовторов
ИЗ
Документ.Продажа КАК Продажа
СГРУППИРОВАТЬ ПО
Продажа.Номер,
Продажа.Дата
ИМЕЮЩИЕ
КОЛИЧЕСТВО(Продажа.Ссылка) > 1
Иногда дубли возникают из-за того, что один и тот же подчиненный документ ошибочно привязан к основанию несколько раз (например, через разные реквизиты или строки табличной части). В таких ситуациях полезно использовать функцию КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Ссылка). Она позволит отсечь ситуации, когда запрос возвращает несколько строк из-за особенностей объединения таблиц (JOIN), но фактически документ один и тот же.
Давайте проанализируем ситуацию: если мы ищем подчиненные документы через связь в табличной части, запрос может вернуть столько строк, сколько строк в ТЧ ссылаются на родителя. Чтобы понять, действительно ли создано два разных документа-дубля, мы пишем так:
ВЫБРАТЬ
СвязанныеДокументы.ДокументОснование,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ СвязанныеДокументы.Ссылка) КАК КолВоРазныхДокументов
ИЗ
КритерийОтбора.СвязанныеДокументы(&Основание) КАК СвязанныеДокументы
СГРУППИРОВАТЬ ПО
СвязанныеДокументы.ДокументОснование
ИМЕЮЩИЕ
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ СвязанныеДокументы.Ссылка) > 1
Подводя итог, можно составить краткую инструкцию для решения подобных задач:
В ИЕРАРХИИ для документов — этот оператор для них бесполезен.СГРУППИРОВАТЬ ПО и ИМЕЮЩИЕ.ГДЕ.Следуя этим правилам, вы сможете строить надежные и быстрые запросы даже в сложных самописных конфигурациях, эффективно управляя связями между документами и контролируя чистоту данных.