Как в запросе 1С выбрать данные из одной таблицы, которых нет в другой?

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

В практике разработки на платформе 1С часто возникает классическая задача: необходимо получить все записи из одной временной таблицы, исключив из результата те строки, которые имеют соответствия в другой таблице. В SQL-терминологии такая операция называется Anti-Join. Давайте подробно разберем, как правильно реализовать этот механизм, проанализируем различные подходы и выясним, какой из них является наиболее оптимальным с точки зрения производительности и надежности.

Способ №1: Использование ЛЕВОГО СОЕДИНЕНИЯ с проверкой на NULL

Этот метод считается "золотым стандартом" в среде разработчиков 1С. Его суть заключается в том, что мы пытаемся соединить основную таблицу (откуда берем данные) с таблицей-фильтром. Для тех строк, которым не нашлось соответствия во второй таблице, поля этой второй таблицы примут значение NULL. Именно этот факт мы и используем в условии отбора.

Рассмотрим по шагам реализацию этого подхода. Предположим, у нас есть ВТ_Данные (таблица со всей информацией) и ВТ_Исключения (таблица с колонкой КлючИсключения, значения которой нужно убрать из результата).

Проанализируем пример кода:


ВЫБРАТЬ
    Данные.Поле1,
    Данные.Поле2,
    Данные.КлючСвязи
ИЗ
    ВТ_Данные КАК Данные
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Исключения КАК Исключения
        ПО Данные.КлючСвязи = Исключения.КлючИсключения
ГДЕ
    Исключения.КлючИсключения ЕСТЬ NULL

Почему этот способ предпочтителен? Выделим основные преимущества:

  1. Производительность: Оптимизаторы СУБД (будь то MS SQL Server или PostgreSQL) крайне эффективно обрабатывают соединения (Join). В большинстве случаев будет построен оптимальный план выполнения запроса.
  2. Безопасность данных: Этот метод корректно обрабатывает ситуации, когда в таблицах встречаются неопределенные значения.
  3. Универсальность: Легко расширить условие связи, если исключение должно строиться по нескольким полям одновременно.

Способ №2: Использование конструкции НЕ В (подзапрос)

Этот вариант часто кажется более интуитивно понятным новичкам, так как он буквально описывает задачу: "выбрать всё, где значение НЕ В списке". Здесь мы используем подзапрос к первой временной таблице.

Разберем, как выглядит такой запрос:


ВЫБРАТЬ
    Вт2.Поле1,
    Вт2.Поле2
ИЗ
    ВТ2 КАК Вт2
ГДЕ
    НЕ Вт2.КлючевоеПоле В
            (ВЫБРАТЬ
                ВТ1.КлючевоеПоле
            ИЗ
                ВТ1 КАК ВТ1)

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

Проблема NULL-значений: В SQL существует так называемая трехзначная логика. Если в подзапросе (в таблице ВТ1) окажется хотя бы одна строка, где КлючевоеПоле имеет значение NULL, то весь результат выражения НЕ В может стать неопределенным (UNKNOWN). В языке запросов 1С это приведет к тому, что запрос вернет пустой результат, даже если в ВТ2 есть сотни несовпадающих строк.

Производительность: На больших объемах данных подзапросы с НЕ В могут работать значительно медленнее, чем левое соединение, так как СУБД может выбрать менее эффективный алгоритм сравнения строк.

Важность индексирования временных таблиц

Независимо от выбранного способа, существует правило, которое нельзя игнорировать: все поля, по которым происходит соединение или поиск, должны быть проиндексированы. Если мы работаем с временными таблицами, это делается на этапе их создания.

Рассмотрим пример правильного создания таблицы-фильтра:


ВЫБРАТЬ
    Источник.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_СписокИсключений
ИЗ
    Справочник.Номенклатура КАК Источник
ГДЕ
    Источник.ПометкаУдаления = ИСТИНА

ИНДЕКСИРОВАТЬ ПО
    Ссылка
;

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

Различие между ЕСТЬ NULL и ЕСТЬNULL()

В процессе написания запросов с левым соединением важно не перепутать два похожих по названию инструмента платформы. Давайте проанализируем разницу:

Подведение итогов

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

  1. Создайте временную таблицу с ключами для исключения и обязательно добавьте ИНДЕКСИРОВАТЬ ПО названию ключевого поля.
  2. Используйте ЛЕВОЕ СОЕДИНЕНИЕ основной таблицы с этой временной таблицей по ключевому полю.
  3. В секции ГДЕ установите условие ПолеПрисоединеннойТаблицы ЕСТЬ NULL.

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

← На главную