Как использовать вложенный запрос в условии ГДЕ по нескольким полям в 1С

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

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

Разбор синтаксической ошибки и ее решение

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


ВЫБРАТЬ
    ВТ_Пользователи.ФизическоеЛицо КАК ФизическоеЛицо,
    ВТ_Пользователи.Пользователь КАК Пользователь
ИЗ
    ВТ_Пользователи КАК ВТ_Пользователи
ГДЕ
    ВТ_Пользователи.ФизическоеЛицо, ВТ_Пользователи.Пользователь В
        (ВЫБРАТЬ
            ВТ_Соответствие.ФизическоеЛицо,
            ВТ_Соответствие.Пользователь
        ИЗ
            ВТ_Соответствие)

При попытке выполнить такой код система выдаст ошибку: «Синтаксическая ошибка ","». Давайте выясним причину. Дело в том, что в языке запросов 1С запятая вне скобок в секции ГДЕ воспринимается парсером как разделитель или окончание выражения. Чтобы система поняла, что мы сравниваем именно набор полей (кортеж), их обязательно нужно заключить в круглые скобки.

Правильный синтаксис будет выглядеть так:


ВЫБРАТЬ
    ВТ_Пользователи.ФизическоеЛицо КАК ФизическоеЛицо,
    ВТ_Пользователи.Пользователь КАК Пользователь
ИЗ
    ВТ_Пользователи КАК ВТ_Пользователи
ГДЕ
    (ВТ_Пользователи.ФизическоеЛицо, ВТ_Пользователи.Пользователь) В
        (ВЫБРАТЬ
            ВТ_Соответствие.ФизическоеЛицо,
            ВТ_Соответствие.Пользователь
        ИЗ
            ВТ_Соответствие)

Теперь запрос отработает корректно. Важно помнить, что количество и порядок полей в левой части (перед оператором В) должны строго соответствовать количеству и порядку полей в списке выборки вложенного запроса.

Особенности трансляции запроса в SQL (MS SQL Server и PostgreSQL)

Проанализируем ситуацию глубже. Хотя на уровне языка 1С мы пишем красивое условие с кортежами, СУБД воспринимают его по-разному. Это критично для понимания производительности вашей системы.

  1. MS SQL Server: Эта СУБД нативно не поддерживает конструкцию (Field1, Field2) IN (SELECT ...). Когда платформа 1С транслирует такой запрос, она превращает его в условие EXISTS. Внутри этого условия создается вложенный подзапрос, где поля связываются через логическое AND. Это превращается в достаточно «тяжелую» конструкцию, которая может замедлить выполнение, если данных много.
  2. PostgreSQL: В отличие от MS SQL, эта СУБД поддерживает конструкторы строк (Row Constructors). Запрос транслируется практически «один в один», что делает его выполнение более естественным и эффективным для этой системы.

Подводные камни при работе с NULL-значениями

Рассмотрим подробнее работу с неопределенными значениями. В языке SQL (и 1С не исключение) сравнение с NULL никогда не дает результат «Истина». Если в ваших таблицах ВТ_Пользователи или ВТ_Соответствие хотя бы в одном из полей кортежа встретится NULL, такая строка не попадет в результат запроса.

Даже если в обеих таблицах в поле ФизическоеЛицо стоит NULL, система посчитает, что они не равны. Если ваша логика предполагает сопоставление записей с пустыми значениями, вам придется предварительно обрабатывать их функцией ЕСТЬNULL(Поле, ЗначениеЗамены).

Оптимизация: когда стоит отказаться от "В" в пользу "СОЕДИНЕНИЯ"

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

Вместо одного сложного запроса с вложенным условием, мы проделаем следующие действия:

  1. Поместим данные для фильтрации во временную таблицу (например, ВТ_Фильтр).
  2. Обязательно проиндексируем эту временную таблицу по всем полям, по которым будет идти сравнение.
  3. Соединим основную таблицу с ВТ_Фильтр через ВНУТРЕННЕЕ СОЕДИНЕНИЕ по нужным полям.

Пример оптимизированного кода:


// 1. Создаем индексированную временную таблицу фильтра
ВЫБРАТЬ
    ВТ_Соответствие.ФизическоеЛицо КАК ФизическоеЛицо,
    ВТ_Соответствие.Пользователь КАК Пользователь
ПОМЕСТИТЬ ВТ_Фильтр
ИЗ
    ВТ_Соответствие КАК ВТ_Соответствие
ИНДЕКСИРОВАТЬ ПО
    ФизическоеЛицо,
    Пользователь
;

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

Такой подход гарантирует предсказуемый план выполнения запроса на уровне СУБД. Использование Hash Match или Merge Join при наличии индексов отработает значительно быстрее, чем трансформированное условие EXISTS с вложенным подзапросом.

Индексация и типы данных

Выясним причину, почему индексация так важна. При сравнении нескольких полей СУБД эффективнее всего использует составные индексы. Если вы используете конструкцию со скобками в ГДЕ, СУБД может перейти к полному сканированию таблицы (Index Scan) вместо быстрого поиска (Index Seek), особенно если порядок полей в индексе не совпадает с порядком полей в вашем условии.

Также проанализируем типы данных. В 1С ФизическоеЛицо и Пользователь — это ссылочные типы. Платформа строго следит за совместимостью типов в кортежах. Если в левой части у вас поле типа СправочникСсылка.Сотрудники, а во вложенном запросе — СправочникСсылка.ФизическиеЛица, запрос не скомпилируется, даже если по смыслу это одно и то же. Всегда проверяйте соответствие типов данных в обеих частях условия.

Итоги

Подводя итог, можно выделить основные правила работы с вложенными запросами по нескольким полям:

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

← На главную