Как использовать колонку временной таблицы в качестве параметра или фильтра в запросе 1С?

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

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

Анализируем причину ошибки: почему нельзя просто указать имя таблицы?

Рассмотрим ситуацию, с которой столкнулся автор темы. В коде была попытка сделать следующее:


ВЫБРАТЬ
    Договор.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_Договор
ИЗ
    Справочник.ДоговорыКонтрагентов КАК Договор
ГДЕ
    Договор.Владелец В (ВТ_ФизЛица.ПлательщикУченика);

При попытке выполнить такой запрос система выдаст ошибку "Поле не найдено". Давайте выясним причину. В языке запросов 1С конструкция В (...) ожидает внутри либо список значений (переданный через параметр-массив), либо вложенный запрос. Временная таблица — это физическая таблица в базе данных (хранящаяся в TempDB сервера SQL). Прямое обращение к ней через точку в условии фильтрации синтаксически недопустимо, так как движок запросов не понимает, из какой именно строки временной таблицы нужно взять значение.

Рассмотрим по шагам, как можно реализовать этот отбор правильно.

Решение №1: Использование вложенного запроса (Semi-join)

Самый простой и логичный способ — превратить обращение к временной таблице в полноценный подзапрос. Это позволяет системе однозначно понять, какие данные мы хотим получить из ВТ_ФизЛица.

Проанализируем исправленный код:


ВЫБРАТЬ
    Договор.Ссылка КАК Ссылка,
    Договор.Владелец КАК Родитель
ПОМЕСТИТЬ ВТ_Договор
ИЗ
    Справочник.ДоговорыКонтрагентов КАК Договор
ГДЕ
    Договор.Владелец В (ВЫБРАТЬ ВТ_ФизЛица.ПлательщикУченика ИЗ ВТ_ФизЛица КАК ВТ_ФизЛица)

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

  1. Безопасность дублей: Если в таблице ВТ_ФизЛица одно и то же лицо встречается несколько раз, основной запрос не "размножит" строки. Он просто проверит наличие совпадения.
  2. Читаемость: Код выглядит лаконично и понятно с точки зрения бизнес-логики.

Решение №2: Использование соединения (JOIN)

Второй способ — это использование ЛЕВОГО СОЕДИНЕНИЯ или ВНУТРЕННЕГО СОЕДИНЕНИЯ. Как отмечают опытные разработчики, для оптимизатора СУБД соединение часто является более предпочтительным и предсказуемым вариантом, чем подзапрос в условии ГДЕ.

Давайте разберем пример использования соединения:


ВЫБРАТЬ
    Договор.Ссылка КАК Ссылка,
    ВТ_ФизЛица.ПлательщикУченика КАК Родитель
ПОМЕСТИТЬ ВТ_Договор
ИЗ
    ВТ_ФизЛица КАК ВТ_ФизЛица
    ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ДоговорыКонтрагентов КАК Договор
    ПО ВТ_ФизЛица.ПлательщикУченика = Договор.Владелец

Важный нюанс: если вам нужно сохранить всех учеников, даже тех, у кого нет договора, используйте ЛЕВОЕ СОЕДИНЕНИЕ. Если же нужны только те, по кому найдены договоры — используйте ВНУТРЕННЕЕ СОЕДИНЕНИЕ или дополнительный фильтр ГДЕ НЕ Договор.Ссылка ЕСТЬ NULL.

Сравнение методов: что выбрать?

Разберем ситуацию более глубоко. В сообщениях форума возник спор: что быстрее? С одной стороны, подзапрос В (ВЫБРАТЬ...) кажется фильтром, а соединение — полной обработкой. На самом деле, современные СУБД (SQL Server, PostgreSQL) часто преобразуют эти конструкции в идентичные планы выполнения.

Однако есть критические различия:

Критически важный момент: Индексация

О чем часто забывают при работе с временными таблицами — это производительность на больших объемах данных. Если в вашей таблице ВТ_ФизЛица более 100-200 записей, обязательно индексируйте поле связи. Без индекса СУБД будет выполнять полное сканирование таблицы (Table Scan) для каждой проверки условия, что катастрофически замедлит работу системы.

Рассмотрим, как правильно добавить индекс:


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

Добавление ключевого слова ИНДЕКСИРОВАТЬ превратит вашу временную таблицу в эффективный инструмент, с которым соединение будет работать мгновенно.

Проблема пустых таблиц

Проанализируем еще одну тонкость. Если временная таблица ВТ_ФизЛица окажется пустой (например, по заданным параметрам не нашлось ни одного ученика), то условие ГДЕ Договор.Владелец В (ВЫБРАТЬ...) приведет к тому, что весь итоговый запрос вернет пустой результат. В некоторых бизнес-сценариях это может быть нежелательно. Если вам нужно видеть "всех, но с пометкой о договоре", используйте только ЛЕВОЕ СОЕДИНЕНИЕ от основной таблицы к договорам.

Итоги и рекомендации

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

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

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

← На главную