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

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

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

В этой статье мы разберем несколько эффективных способов реализации такого отбора, проанализируем логику работы агрегатных функций с типом Булево и рассмотрим вопросы производительности запросов.

Способ 1. Использование функции МИНИМУМ для логических полей

Это самый лаконичный и быстрый способ. В языке запросов 1С значения типа Булево при сравнении и агрегации ведут себя подобно числам: Ложь трактуется как 0, а Истина — как 1. Следовательно, Ложь всегда меньше, чем Истина.

Проанализируем ситуацию: если в табличной части хотя бы один сотрудник НЕ помечен на удаление (его ПометкаУдаления = Ложь), то минимальное значение этого поля по всем строкам документа будет равно Ложь. Если же абсолютно все сотрудники помечены, то и минимальным, и максимальным значением будет Истина.

Рассмотрим пример реализации такого запроса:


ВЫБРАТЬ
    ВозвратЗадолженности.Ссылка КАК Ссылка
ИЗ
    Документ.ВозвратСотрудникомЗадолженности.Задолженности КАК ВозвратЗадолженности
СГРУППИРОВАТЬ ПО
    ВозвратЗадолженности.Ссылка
ИМЕЮЩИЕ
    МИНИМУМ(ВозвратЗадолженности.Сотрудник.ПометкаУдаления) = ИСТИНА

Почему это работает? Рассмотрим математическую модель. Допустим, в документе 3 строки:

  1. Сотрудник 1: ПометкаУдаления = Истина (1)
  2. Сотрудник 2: ПометкаУдаления = Ложь (0)
  3. Сотрудник 3: ПометкаУдаления = Истина (1)

Функция МИНИМУМ(1, 0, 1) вернет 0 (Ложь). Документ не попадет в выборку. Если же во всех строках будет 1, то МИНИМУМ(1, 1, 1) вернет 1 (Истина), и условие ИМЕЮЩИЕ будет выполнено.

Способ 2. Условное суммирование (ВЫБОР...КОГДА)

Этот метод считается более универсальным и «читаемым» для многих разработчиков, так как он явно переводит логику в числовой формат. Мы присваиваем каждой строке вес: 0, если условие соблюдено, и 1, если нет. Если сумма весов по документу равна 0, значит, «плохих» строк в нем нет.

Посмотрим на пример кода:


ВЫБРАТЬ
    ТабЧасть.Ссылка КАК Ссылка
ИЗ
    Документ.ВозвратСотрудникомЗадолженности.Задолженности КАК ТабЧасть
СГРУППИРОВАТЬ ПО
    Ссылка
ИМЕЮЩИЕ
    СУММА(ВЫБОР
            КОГДА ТабЧасть.Сотрудник.ПометкаУдаления = ЛОЖЬ
                ТОГДА 1
            ИНАЧЕ 0
        КОНЕЦ) = 0

Разберем, что здесь происходит. Мы проходим по каждой строке табличной части. Если мы встречаем сотрудника без пометки удаления, мы прибавляем к сумме единицу. Если в итоге сумма осталась равной нулю, значит, ни одного «живого» сотрудника в документе не нашлось. Этот метод удобен тем, что условие внутри ВЫБОР можно легко усложнять, добавляя проверки на пустые ссылки или другие реквизиты.

Способ 3. Сравнение общего количества строк с количеством «помеченных»

Еще один надежный вариант — посчитать, сколько всего строк в табличной части документа, и сравнить это число с количеством строк, которые удовлетворяют нашему условию. Если эти числа совпадают, значит, условие выполняется для всех строк без исключения.


ВЫБРАТЬ
    ТЧ.Ссылка КАК Ссылка,
    СУММА(ВЫБОР
            КОГДА ТЧ.Сотрудник.ПометкаУдаления
                ТОГДА 1
            ИНАЧЕ 0
        КОНЕЦ) КАК КолвоПомеченных,
    КОЛИЧЕСТВО(ТЧ.НомерСтроки) КАК ОбщееКолвоСтрок
ПОМЕСТИТЬ ВТ_Статистика
ИЗ
    Документ.ВозвратСотрудникомЗадолженности.Задолженности КАК ТЧ
СГРУППИРОВАТЬ ПО
    ТЧ.Ссылка;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_Статистика.Ссылка
ИЗ
    ВТ_Статистика КАК ВТ_Статистика
ГДЕ
    ВТ_Статистика.КолвоПомеченных = ВТ_Статистика.ОбщееКолвоСтрок
    И ВТ_Статистика.ОбщееКолвоСтрок > 0

Обратите внимание на условие ОбщееКолвоСтрок > 0. Это важный нюанс: если в документе вообще нет строк в табличной части, его статус может быть неопределенным с точки зрения бизнес-логики. Данный запрос позволяет четко отсечь пустые документы.

Способ 4. Метод исключения (Отрицание условия)

С точки зрения производительности СУБД (особенно на больших объемах данных), операции группировки и агрегации (SUM, MIN) могут быть достаточно «тяжелыми». Иногда эффективнее применить метод исключения: найти все документы, где есть хотя бы один непомеченный сотрудник, и исключить их из общего списка.


ВЫБРАТЬ
    ДокументОбъект.Ссылка
ИЗ
    Документ.ВозвратСотрудникомЗадолженности КАК ДокументОбъект
ГДЕ
    ДокументОбъект.Ссылка В
            (ВЫБРАТЬ РАЗЛИЧНЫЕ
                ТЧ.Ссылка
            ИЗ
                Документ.ВозвратСотрудникомЗадолженности.Задолженности КАК ТЧ)
    И НЕ ДокументОбъект.Ссылка В
                (ВЫБРАТЬ РАЗЛИЧНЫЕ
                    ТЧ.Ссылка
                ИЗ
                    Документ.ВозвратСотрудникомЗадолженности.Задолженности КАК ТЧ
                ГДЕ
                    ТЧ.Сотрудник.ПометкаУдаления = ЛОЖЬ)

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

Важные нюансы и оптимизация

При написании таких запросов следует помнить о нескольких технических моментах:

  1. Обращение через точку: Конструкция ТЧ.Сотрудник.ПометкаУдаления вызывает неявное левое соединение (LEFT JOIN) с таблицей справочника Сотрудники. Если табличная часть содержит тысячи строк, это может привести к падению производительности. В высоконагруженных системах лучше сначала отобрать помеченных сотрудников во временную таблицу, а затем соединять её с табличной частью документа.
  2. Пустые значения (NULL): Если поле Сотрудник не заполнено, обращение к его пометке удаления вернет NULL. Агрегатные функции игнорируют NULL, что может исказить результат. Всегда полезно добавлять проверку на ЗНАЧЕНИЕ(Справочник.Сотрудники.ПустаяСсылка).
  3. Пустые табличные части: Группировка по табличной части никогда не вернет ссылки на документы, у которых в этой таблице 0 записей. Если вам нужно найти и такие документы тоже, начинайте выборку из основной таблицы документа (Документ.Имя), а к табличной части присоединяйтесь через ЛЕВОЕ СОЕДИНЕНИЕ.

Подводя итог, можно сказать, что выбор конкретного метода зависит от объема данных и требований к чистоте выборки (нужны ли пустые документы). Для большинства повседневных задач метод с МИНИМУМ() является оптимальным по соотношению краткости и эффективности.

← На главную