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

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

При разработке и доработке конфигураций 1С (в частности, «Управление торговлей 10.3») часто возникает типовая задача: по имеющемуся документу-основанию (например, ЗаказПокупателя) найти созданные на его базе подчиненные документы конкретного типа (например, РеализацияТоваровУслуг). Разберем типичные ошибки начинающих разработчиков при решении этой задачи и рассмотрим надежные программные способы выборки данных.

Анализ типичных ошибок при отборе подчиненных документов

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

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

Способ 1. Использование критерия отбора «СвязанныеДокументы» через запрос

Критерий отбора — это встроенный механизм платформы 1С, который объединяет ссылки на различные документы и их реквизиты. В конфигурации «Управление торговлей 10.3» критерий СвязанныеДокументы содержит реквизиты шапок и табличных частей, связанные со структурой подчиненности. Это наиболее универсальный подход, так как связь реализации с заказом может храниться не только в шапке (Сделка), но и построчно в табличной части (Товары.ЗаказПокупателя).

Посмотрим на пример запроса, отбирающего только документы реализации:


Функция ПолучитьРеализацииПоЗаказу(ДокументОснование) Экспорт

    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗРЕШЕННЫЕ
        |    Связанные.Ссылка КАК Ссылка
        |ИЗ
        |    КритерийОтбора.СвязанныеДокументы(&ЗначениеКритерияОтбора) КАК Связанные
        |ГДЕ
        |    Связанные.Ссылка ССЫЛКА Документ.РеализацияТоваровУслуг";

    Запрос.УстановитьПараметр("ЗначениеКритерияОтбора", ДокументОснование);

    // Выгружаем результат в виде массива ссылок
    Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");

КонецФункции

Обратим внимание: вызов метода ВыгрузитьКолонку("Ссылка") преобразует колонку таблицы значений в простой массив, с которым удобно работать дальше в коде.

Способ 2. Прямой запрос к таблице документа реализации

Если бизнес-логика конфигурации жестко регламентирует хранение документа-основания в шапке накладной (в реквизите Сделка), можно обратиться напрямую к таблице документов реализации. Разберем по шагам, как построить такой запрос:


Функция НайтиНакладныеПоСделке(ДокументОснование) Экспорт

    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |    Реализация.Ссылка КАК Ссылка
        |ИЗ
        |    Документ.РеализацияТоваровУслуг КАК Реализация
        |ГДЕ
        |    Реализация.Сделка = &Сделка";

    Запрос.УстановитьПараметр("Сделка", ДокументОснование);

    Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");

КонецФункции

В этом примере мы не используем дополнительную проверку Реализация.Сделка ССЫЛКА Документ.ЗаказПокупателя, поскольку передача конкретной ссылки ДокументОснование в параметр &Сделка автоматически фильтрует записи по совпадению типа и конкретного значения.

Важное замечание для УТ 10.3: прямой запрос к шапке может не найти реализацию, если в договоре контрагента учет взаиморасчетов ведется не «По заказам», а строки реализации привязаны к разным заказам покупателя. В таком случае связь хранится в табличной части РеализацияТоваровУслуг.Товары в колонке ЗаказПокупателя. Для полного поиска прямым запросом потребовалось бы объединение с табличной частью, поэтому использование критерия отбора из первого способа предпочтительнее.

Способ 3. Программный метод менеджера критериев отбора (без текста запроса)

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


Функция ПолучитьПодчиненныеРеализацииОбъектно(ДокументОснование) Экспорт

    МассивРезультат = Новый Массив;
    ВсеСвязанные = КритерииОтбора.СвязанныеДокументы.Найти(ДокументОснование);

    Для Каждого ТекСсылка Из ВсеСвязанные Цикл
        Если ТипЗнч(ТекСсылка) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда
            МассивРезультат.Добавить(ТекСсылка);
        КонецЕсли;
    КонецЦикла;

    Возврат МассивРезультат;

КонецФункции

Этот способ удобен тем, что не требует написания текста запроса и инициализации объекта Запрос, работая со штатными коллекциями платформы.

Способ 4. Получение единственной ссылки вместо списка или таблицы

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


Функция ПолучитьПервуюРеализацию(ДокументОснование) Экспорт

    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |    Связанные.Ссылка КАК Ссылка
        |ИЗ
        |    КритерийОтбора.СвязанныеДокументы(&ДокументОснование) КАК Связанные
        |ГДЕ
        |    Связанные.Ссылка ССЫЛКА Документ.РеализацияТоваровУслуг";

    Запрос.УстановитьПараметр("ДокументОснование", ДокументОснование);

    Выборка = Запрос.Выполнить().Выбрать();
    Если Выборка.Следующий() Тогда
        Возврат Выборка.Ссылка;
    КонецЕсли;

    Возврат Неопределено;

КонецФункции

Конструкция ПЕРВЫЕ 1 и последующая работа через объект ВыборкаИзРезультатаЗапроса исключают выделение лишней памяти под создание таблицы значений и сразу возвращают нужный ссылочный тип данных либо Неопределено, если документ не найден.

Ограничения механизмов отбора

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

  1. Глубина связей: критерий отбора возвращает только прямые связи первого уровня. Если заказ сначала породил СчетНаОплатуПокупателю, а реализация оформлена уже на основании счета (без явного указания заказа в реализации), критерий не свяжет накладную с заказом напрямую. В таком случае требуется рекурсивный обход дерева связей.
  2. Состав метаданных: платформа видит только те реквизиты, которые включены в состав критерия в дереве конфигурации. Если в конфигурацию был добавлен новый реквизит связи, но разработчик забыл включить его в состав критерия СвязанныеДокументы, платформа не отобразит связь в результатах поиска.
← На главную