Как правильно использовать временную таблицу в условии запроса 1С

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

Работа с запросами в системе 1С:Предприятие 8 требует не только понимания синтаксиса, но и знания механизмов работы платформы с СУБД. Одной из частых задач является использование данных из временной таблицы для фильтрации основного набора записей. Однако на этом пути начинающие разработчики часто сталкиваются с логическими ошибками, которые приводят либо к пустому результату, либо к существенному замедлению работы программы. Рассмотрим подробно, как правильно указать временную таблицу в условии и какие ошибки чаще всего встречаются в коде.

Разбор исходной ситуации и выявление логических ошибок

Проанализируем фрагмент кода, где разработчик пытается выбрать контактных лиц, чьи родители не входят в предварительно сформированную временную таблицу Группы. Основная проблема заключалась в некорректном использовании ЛЕВОГО СОЕДИНЕНИЯ и противоречивых условиях в блоке ГДЕ.

Первая критическая ошибка заключалась в условии соединения: ПО Группы.Ссылка = КонтактныеЛица.Ссылка. Если таблица Группы содержит только родительские элементы, а в основной выборке мы ищем подчиненные элементы, то такое равенство ссылок практически никогда не даст результата, так как объект не может быть одновременно и «родителем для самого себя», и «дочерним элементом», который мы ищем по фильтру.

Вторая ошибка — использование временной таблицы Группы как основной (первой в списке ИЗ), в то время как условие в ГДЕ пытается исключить данные на основе этой же таблицы. Если мы выбираем данные ИЗ таблицы А и при этом говорим «где данные НЕ В таблице А», мы гарантированно получим пустой результат.

Шаг 1: Правильная работа с разыменованием ссылок

В 1С существует понятие «обращение через точку» (разыменование ссылки). В исходном запросе часто встречалось написание КонтактныеЛица.Ссылка.Родитель. Проанализируем, почему это плохо. Поле Ссылка уже содержит уникальный идентификатор записи, а Родитель — это другое поле той же самой таблицы справочника.

Когда вы пишете КонтактныеЛица.Ссылка.Родитель, платформа вынуждена делать неявное соединение таблицы справочника самой с собой, чтобы получить значение поля. Это создает лишнюю нагрузку на SQL-сервер. Правильно обращаться напрямую к полю: КонтактныеЛица.Родитель. Это правило касается любых стандартных и дополнительных реквизитов: КонтактныеЛица.Наименование вместо КонтактныеЛица.Ссылка.Наименование.

Шаг 2: Использование конструкции В и НЕ В с временными таблицами

Для того чтобы указать временную таблицу в условии, мы можем использовать подзапрос к ней. Рассмотрим, как это выглядит в исправленном виде:


ВЫБРАТЬ
    КонтактныеЛица.Ссылка КАК Ссылка,
    КонтактныеЛица.Родитель КАК Родитель
ИЗ
    Справочник.КонтактныеЛица КАК КонтактныеЛица
ГДЕ
    НЕ КонтактныеЛица.Родитель В (ВЫБРАТЬ Группы.Ссылка ИЗ Группы)
    И НЕ КонтактныеЛица.ЭтоГруппа

В данном примере мы выбираем всех контактных лиц, чей родитель отсутствует во временной таблице Группы. Обратите внимание, что внутри скобок после оператора В мы обязательно должны написать полноценный микро-запрос ВЫБРАТЬ ... ИЗ ....

Шаг 3: Оптимизация через ЛЕВОЕ СОЕДИНЕНИЕ

Хотя использование оператора НЕ В интуитивно понятно, с точки зрения производительности (особенно на больших объемах данных) эффективнее использовать ЛЕВОЕ СОЕДИНЕНИE с последующей проверкой на NULL. Разберем этот метод по шагам:

  1. Присоединяем временную таблицу к основной по полю, которое мы хотим проверить (например, по родителю).
  2. В блоке ГДЕ указываем, что поле из присоединенной таблицы должно быть равно NULL.
  3. Это будет означать, что для записи из основной таблицы не нашлось соответствия во временной таблице.

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


ВЫБРАТЬ
    КонтактныеЛица.Ссылка КАК Ссылка
ИЗ
    Справочник.КонтактныеЛица КАК КонтактныеЛица
    ЛЕВОЕ СОЕДИНЕНИЕ Группы КАК Группы
    ПО КонтактныеЛица.Родитель = Группы.Ссылка
ГДЕ
    Группы.Ссылка ЕСТЬ NULL
    И НЕ КонтактныеЛица.ЭтоГруппа

Такой подход позволяет оптимизатору СУБД более эффективно построить план выполнения запроса, используя индексы.

Шаг 4: Индексация временных таблиц

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

При создании временной таблицы добавьте ключевое слово ИНДЕКСИРОВАТЬ ПО:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    КонтактныеЛица.Родитель КАК Ссылка
ПОМЕСТИТЬ Группы
ИЗ
    Справочник.КонтактныеЛица КАК КонтактныеЛица
ГДЕ
    КонтактныеЛица.Ссылка В ИЕРАРХИИ(&СсылкаГруппы)
ИНДЕКСИРОВАТЬ ПО
    Ссылка
;

Важный нюанс: Индексировать стоит только те поля, по которым реально происходит поиск или соединение. Избыточное количество индексов также может замедлить работу из-за затрат на их создание.

Шаг 5: Особенности условия В ИЕРАРХИИ

В исходном запросе использовалось условие В ИЕРАРХИИ(&СсылкаГруппы). Нужно помнить, что это одно из самых «тяжелых» условий в 1С. Платформа преобразует его в сложный SQL-запрос, который ищет все вложенные элементы на всех уровнях. Если структура справочника очень глубокая, а записей сотни тысяч, старайтесь минимизировать количество таких вызовов. Помещение результатов иерархического поиска во временную таблицу (как и пытался сделать автор темы) — это верная стратегия, так как она позволяет выполнить тяжелый поиск один раз, а затем использовать готовый плоский список.

Шаг 6: Проверка логики отрицания

Проанализируем еще один момент из обсуждения — проверку типов событий. Условие ТипСобытия <> ЗНАЧЕНИЕ(...) И ТипСобытия <> ЗНАЧЕНИЕ(...) работает корректно только тогда, когда ТипСобытия не является NULL. Если вы используете ЛЕВОЕ СОЕДИНЕНИЕ с таблицей событий, и событие для участника не найдено, проверка на неравенство конкретному значению вернет ЛОЖЬ (так как NULL не равен и не «не равен» значению в классическом понимании логики SQL в данном контексте).

Для корректной фильтрации в таких случаях следует либо переносить условия в блок ПО соединения, либо явно обрабатывать NULL через функцию ЕСТЬNULL(ТипСобытия, ЗНАЧЕНИЕ(...)).

Итоговый алгоритм построения эффективного запроса:

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

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

← На главную