В практике разработки на платформе 1С часто возникает классическая задача: необходимо получить все записи из одной временной таблицы, исключив из результата те строки, которые имеют соответствия в другой таблице. В SQL-терминологии такая операция называется Anti-Join. Давайте подробно разберем, как правильно реализовать этот механизм, проанализируем различные подходы и выясним, какой из них является наиболее оптимальным с точки зрения производительности и надежности.
Этот метод считается "золотым стандартом" в среде разработчиков 1С. Его суть заключается в том, что мы пытаемся соединить основную таблицу (откуда берем данные) с таблицей-фильтром. Для тех строк, которым не нашлось соответствия во второй таблице, поля этой второй таблицы примут значение NULL. Именно этот факт мы и используем в условии отбора.
Рассмотрим по шагам реализацию этого подхода. Предположим, у нас есть ВТ_Данные (таблица со всей информацией) и ВТ_Исключения (таблица с колонкой КлючИсключения, значения которой нужно убрать из результата).
Проанализируем пример кода:
ВЫБРАТЬ
Данные.Поле1,
Данные.Поле2,
Данные.КлючСвязи
ИЗ
ВТ_Данные КАК Данные
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Исключения КАК Исключения
ПО Данные.КлючСвязи = Исключения.КлючИсключения
ГДЕ
Исключения.КлючИсключения ЕСТЬ NULL
Почему этот способ предпочтителен? Выделим основные преимущества:
Этот вариант часто кажется более интуитивно понятным новичкам, так как он буквально описывает задачу: "выбрать всё, где значение НЕ В списке". Здесь мы используем подзапрос к первой временной таблице.
Разберем, как выглядит такой запрос:
ВЫБРАТЬ
Вт2.Поле1,
Вт2.Поле2
ИЗ
ВТ2 КАК Вт2
ГДЕ
НЕ Вт2.КлючевоеПоле В
(ВЫБРАТЬ
ВТ1.КлючевоеПоле
ИЗ
ВТ1 КАК ВТ1)
Несмотря на наглядность, у этого способа есть несколько критических нюансов, о которых важно помнить каждому программисту 1С. Выясним причину возможных проблем:
Проблема NULL-значений: В SQL существует так называемая трехзначная логика. Если в подзапросе (в таблице ВТ1) окажется хотя бы одна строка, где КлючевоеПоле имеет значение NULL, то весь результат выражения НЕ В может стать неопределенным (UNKNOWN). В языке запросов 1С это приведет к тому, что запрос вернет пустой результат, даже если в ВТ2 есть сотни несовпадающих строк.
Производительность: На больших объемах данных подзапросы с НЕ В могут работать значительно медленнее, чем левое соединение, так как СУБД может выбрать менее эффективный алгоритм сравнения строк.
Независимо от выбранного способа, существует правило, которое нельзя игнорировать: все поля, по которым происходит соединение или поиск, должны быть проиндексированы. Если мы работаем с временными таблицами, это делается на этапе их создания.
Рассмотрим пример правильного создания таблицы-фильтра:
ВЫБРАТЬ
Источник.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_СписокИсключений
ИЗ
Справочник.Номенклатура КАК Источник
ГДЕ
Источник.ПометкаУдаления = ИСТИНА
ИНДЕКСИРОВАТЬ ПО
Ссылка
;
Без индекса по полю Ссылка система будет вынуждена выполнять полное сканирование таблиц при каждом сопоставлении, что на тысячах строк приведет к колоссальным задержкам.
В процессе написания запросов с левым соединением важно не перепутать два похожих по названию инструмента платформы. Давайте проанализируем разницу:
ЕСТЬ NULL (пишется раздельно): Это логический оператор, используемый исключительно в секции ГДЕ. Он проверяет, является ли значение в колонке отсутствующим. Именно его мы используем для отбора строк, для которых не нашлось пары при соединении.ЕСТЬNULL(Поле, ЗначениеЗамены) (пишется слитно): Это функция преобразования. Она говорит системе: "Если в этом поле NULL, замени его на вот это значение (например, на 0 или пустую строку)". Эту функцию нельзя использовать как условие фильтрации в ГДЕ для решения нашей задачи.Для эффективного исключения данных из выборки в 1С мы рекомендуем придерживаться следующего алгоритма:
ИНДЕКСИРОВАТЬ ПО названию ключевого поля.ЛЕВОЕ СОЕДИНЕНИЕ основной таблицы с этой временной таблицей по ключевому полю.ГДЕ установите условие ПолеПрисоединеннойТаблицы ЕСТЬ NULL.Такой подход обеспечит максимальную скорость работы кода и гарантирует корректность результата независимо от наличия пустых значений в данных.