Как реализовать запрос-исключение в 1С через конструкцию ИМЕЮЩИЕ

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

В практике разработки на платформе 1С часто возникает задача, которую в классическом SQL называют «разностью множеств». Например, нужно найти всех производителей, которые выпускают компьютеры, но при этом принципиально не производят ноутбуки. Стандартные подходы вроде ГДЕ НЕ В (ВЫБРАТЬ...) не всегда оптимальны, а оператор EXCEPT в языке запросов 1С отсутствует. В этой статье мы подробно разберем, как эффективно решить эту задачу с помощью конструкции ИМЕЮЩИЕ (HAVING) и других профессиональных приемов.

Метод 1: Использование агрегатных функций с условием ВЫБОР

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

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


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

Почему это работает:

  1. В секции ГДЕ мы ограничиваем выборку только интересующими нас категориями, чтобы не обрабатывать лишние данные (например, принтеры).
  2. В секции СГРУППИРОВАТЬ ПО мы схлопываем все записи по каждому производителю.
  3. В секции ИМЕЮЩИЕ мы проверяем результат агрегации. Первая сумма покажет, сколько раз встретились компьютеры. Если больше 0 — производитель нам подходит. Вторая сумма считает ноутбуки. Если она равна 0 — значит, этот производитель ноутбуки не выпускает.

Метод 2: Присвоение весов (уникальных сумм)

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

Рассмотрим пример, где "Ноутбуки" имеют вес 1, а "Компьютеры" — вес 2:


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

Проанализируем логику: если сумма равна 2, это гарантированно означает, что у производителя есть компьютеры (2), но нет ноутбуков (1). Если бы были и те, и другие, сумма была бы равна 3 (2+1). Если бы были только ноутбуки — 1. Этот метод позволяет одной проверкой отсекать сложные комбинации признаков.

Метод 3: Использование функции МАКСИМУМ вместо СУММА

Выясним причину, по которой опытные разработчики иногда предпочитают МАКСИМУМ. Если в базе данных на одного производителя может приходиться несколько записей с типом "Компьютеры" (например, разные модели), то СУММА вернет число больше 1. Если ваше условие жестко завязано на СУММА(...) = 1, такой производитель ошибочно не попадет в выборку.

Посмотрим на более устойчивый вариант кода:


ИМЕЮЩИЕ
    МАКСИМУМ(ВЫБОР КОГДА Т.ТипОборудования.Наименование = "Компьютеры" ТОГДА 1 ИНАЧЕ 0 КОНЕЦ) = 1
    И МАКСИМУМ(ВЫБОР КОГДА Т.ТипОборудования.Наименование = "Ноутбуки" ТОГДА 1 ИНАЧЕ 0 КОНЕЦ) = 0

Здесь мы работаем с логическими флагами: "есть хотя бы один" (1) или "нет ни одного" (0). Это делает запрос более надежным при наличии дублей в измерениях регистра.

Метод 4: Использование временных таблиц (Стандарт 1С)

Несмотря на удобство ИМЕЮЩИЕ, стандарты разработки 1С часто рекомендуют использовать временные таблицы, особенно на огромных массивах данных. Это позволяет избежать группировки «всего подряд» и сделать запрос более прозрачным для оптимизатора СУБД.

Разберем этот подход по шагам:

  1. Сначала выберем всех производителей ноутбуков (тех, кого надо исключить) во временную таблицу.
  2. Затем выберем производителей компьютеров и соединим их с первой таблицей через ЛЕВОЕ СОЕДИНЕНИЕ.
  3. Оставим только те записи, где не нашлось соответствия во второй таблице (проверка на NULL).

// Шаг 1: Получаем список исключений
ВЫБРАТЬ РАЗЛИЧНЫЕ
    Т.Производитель КАК Производитель
ПОМЕСТИТЬ ВТ_ПроизводителиНоутбуков
ИЗ
    РегистрСведений.Оборудование КАК Т
ГДЕ
    Т.ТипОборудования.Наименование = "Ноутбуки";

////////////////////////////////////////////////////////////////////////////////
// Шаг 2: Основная выборка с исключением
ВЫБРАТЬ РАЗЛИЧНЫЕ
    Т_Компьютеры.Производитель КАК Производитель
ИЗ
    РегистрСведений.Оборудование КАК Т_Компьютеры
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ПроизводителиНоутбуков КАК Исключения
        ПО Т_Компьютеры.Производитель = Исключения.Производитель
ГДЕ
    Т_Компьютеры.ТипОборудования.Наименование = "Компьютеры"
    И Исключения.Производитель ЕСТЬ NULL

Преимущества этого метода:

Сводная таблица методов

Подведем итог и сравним подходы, чтобы понять, какой выбрать в вашей ситуации:

  1. ИМЕЮЩИЕ + СУММА: Отлично подходит для простых отчетов и небольших таблиц. Минимум кода.
  2. ИМЕЮЩИЕ + ВЕСА: Идеально для проверки множества условий (например, "делает А и Б, но не делает В и Г").
  3. Временные таблицы + ЕСТЬ NULL: Самый масштабируемый и "профессиональный" метод для высоконагруженных систем.

Используя эти приемы, вы сможете эффективно реализовывать даже самые сложные условия исключения в запросах 1С, обеспечивая при этом высокую скорость работы системы.

← На главную