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

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

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

Сложность заключается в том, что обычное условие ГДЕ ТЧ.Поле = Истина выберет документы, в которых есть хотя бы одна такая строка, но проигнорирует наличие «плохих» строк в том же документе. В этой статье мы подробно разберем несколько методов решения этой задачи, проанализируем их производительность и рассмотрим сложные случаи.

Метод 1. Использование отрицания (подзапрос исключения)

Это самый популярный и интуитивно понятный способ. Его суть заключается в том, чтобы выбрать все документы, за исключением тех, в которых есть хотя бы одна «неправильная» строка. Рассмотрим ситуацию, когда нам нужны документы ЛистОбследования, где поле Сдал в табличной части тчПрофосмотр равно Истина абсолютно во всех записях.

Разберем логику построения такого запроса по шагам:

  1. Сначала мы описываем основной запрос к шапке документа.
  2. Затем в секции ГДЕ добавляем условие, исключающее ссылки, которые встречаются в выборке «невыполненных» строк.

Пример реализации:


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

Проанализируем этот код: подзапрос находит все ссылки на документы, где хотя бы один врач не пройден (Сдал = ЛОЖЬ). Основной запрос берет все документы и отсекает те, что попали в этот «черный список». Это надежный метод, который корректно обрабатывает документы с разным количеством строк.

Метод 2. Агрегация через функцию МИНИМУМ

В языке запросов 1С булевы значения сравнимы: ЛОЖЬ всегда меньше, чем ИСТИНА. Эту особенность можно использовать для эффективной группировки. Если минимальное значение поля Сдал в документе равно ИСТИНА, значит, в нем физически не может быть ни одной строки со значением ЛОЖЬ.

Рассмотрим пример запроса с группировкой:


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

Этот метод лаконичен и часто работает быстрее, так как не требует вложенных конструкций В (...). Однако стоит помнить, что при таком подходе мы работаем напрямую с табличной частью. Чтобы получить данные из шапки документа, этот запрос следует использовать как временную таблицу или вложить его в основной.

Метод 3. Сравнение количества строк

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

Посмотрим на реализацию через конструкцию ВЫБОР:


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

Здесь мы суммируем единицы только для тех строк, где Сдал = ИСТИНА, и сравниваем результат с общим числом строк в этой группе (документе). Этот метод удобен, если условие более сложное, чем простое булево поле.

Сложный случай: условие с исключениями (кейс «Профпатолог»)

Иногда бизнес-логика требует более тонкой настройки. Например, нужно, чтобы все врачи в списке имели отметку Сдал = Истина, но конкретный специалист (например, Профпатолог) должен иметь Сдал = Ложь, так как он закрывает лист последним и на момент проверки его статус должен быть отрицательным.

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

  1. Любой врач (кроме Профпатолога) имеет Сдал = ЛОЖЬ.
  2. Профпатолог имеет Сдал = ИСТИНА (если по логике задачи он должен быть еще не сдан).

Проанализируем пример кода для такой задачи:


ВЫБРАТЬ
    Лист.Ссылка
ИЗ
    Документ.ЛистОбследования КАК Лист
ГДЕ
    НЕ Лист.Ссылка В (
        ВЫБРАТЬ
            ТЧ.Ссылка
        ИЗ
            Документ.ЛистОбследования.тчПрофосмотр КАК ТЧ
        ГДЕ
            (ТЧ.Номенклатура <> &Профпатолог И ТЧ.Сдал = ЛОЖЬ)
            ИЛИ (ТЧ.Номенклатура = &Профпатолог И ТЧ.Сдал = ИСТИНА)
    )

Такой подход позволяет гибко настраивать требования к «идеальному» документу, описывая в подзапросе только те ситуации, которые нас не устраивают.

Оптимизация: Левое соединение вместо НЕ В

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

Разберем этот механизм:

  1. Выбираем все документы.
  2. Левым соединением присоединяем к ним таблицу «плохих» строк.
  3. В условии фильтруем только те документы, для которых «плохая» строка ЕСТЬ NULL (т.е. соединение не нашло ни одного нарушения).

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

Этот способ считается наиболее производительным на СУБД MS SQL Server и PostgreSQL при работе с миллионами записей.

Важные нюансы и архитектурные советы

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

1. Пустые табличные части. Если в документе вообще нет строк, то подзапрос «плохих строк» ничего не вернет, и документ попадет в итоговую выборку. Если по логике системы документ без строк не считается «валидным», необходимо добавить проверку на наличие хотя бы одной строки через ВНУТРЕННЕЕ СОЕДИНЕНИЕ с табличной частью или условие КОЛИЧЕСТВО > 0.

2. Использование регистров. Если проверка «все ли строки заполнены» выполняется очень часто (например, в динамическом списке списка документов), это создаст высокую нагрузку на сервер, так как табличные части документов не индексируются по произвольным полям вроде Сдал. Рекомендуется при проведении документа записывать статус готовности в отдельный Регистр сведений. В таком случае запрос станет максимально простым и быстрым, обращаясь всего к одному индексированному полю ресурса регистра.

Мы рассмотрели основные способы получения документов с полностью валидными табличными частями. Выбор конкретного метода зависит от объема ваших данных и сложности условий, но для большинства повседневных задач метод с НЕ Ссылка В (ПОДЗАПРОС) является оптимальным балансом между читаемостью кода и скоростью разработки.

← На главную