Почему запрос с подзапросом по временной таблице в параметрах среза последних возвращает пустой результат?

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

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

Анализ синтаксической ошибки: лишние кавычки в теле подзапроса

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


ФизическоеЛицо В (""ВЫБРАТЬ
                      ФизЛица.ФизическоеЛицо КАК ФизическоеЛицо
                  ИЗ
                      ФизЛица КАК ФизЛица"")

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

Чтобы запрос отработал корректно, необходимо удалить обрамляющие кавычки:


ФизическоеЛицо В (ВЫБРАТЬ
                      ФизЛица.ФизическоеЛицо
                  ИЗ
                      ФизЛица КАК ФизЛица)

Как правильно вызывать конструктор запроса для вложенных таблиц

Ошибочные кавычки часто появляются в коде из-за попытки разработчика открыть конструктор запроса для редактирования вложенного выражения. Если в тексте модуля попытаться вызвать конструктор внутри незавершенного подзапроса, конфигуратор может выдать синтаксическую ошибку.

Разберем по шагам правильные приемы вызова конструктора запросов:

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

Почему подзапрос в параметрах виртуальной таблицы не рекомендуется

Несмотря на то, что после удаления кавычек запрос начнет выполняться, помещение вложенных запросов и обращений к временным таблицам в параметры виртуальных таблиц (таких как СрезПоследних или ОстаткиИОбороты) считается неоптимальной практикой по стандартам разработки 1С. Рассмотрим причины:

  1. Снижение производительности СУБД: оптимизатор реляционной базы данных часто не может построить эффективный план выполнения для вычисления среза при наличии вложенного подзапроса в условиях. Вместо точечного поиска по индексам СУБД может применить полное сканирование таблицы или неэффективные вложенные циклы.
  2. Проблема дубликатов и значений NULL: если в исходном справочнике Сотрудники одно физическое лицо встречается несколько раз (например, при внутреннем или внешнем совместительстве), временная таблица без ключевого слова РАЗЛИЧНЫЕ будет содержать дубликаты. Наличие незаполненных значений (NULL или пустых ссылок) внутри предикатов IN (SELECT ...) также способно исказить работу логики условий СУБД.

Рекомендуемый вариант 1: Использование внутреннего соединения с временной таблицей

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

Посмотрим на пример правильного построения запроса:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    Сотрудники.ФизическоеЛицо КАК ФизическоеЛицо
ПОМЕСТИТЬ ВТ_ФизЛица
ИЗ
    Справочник.Сотрудники КАК Сотрудники
ГДЕ
    Сотрудники.Ссылка В(&МассивОбъектов)
    И Сотрудники.ФизическоеЛицо ЕСТЬ НЕ NULL
    И Сотрудники.ФизическоеЛицо <> ЗНАЧЕНИЕ(Справочник.ФизическиеЛица.ПустаяСсылка)

ИНДЕКСИРОВАТЬ ПО
    ФизическоеЛицо
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ЛицевыеСчета.ФизическоеЛицо КАК ФизическоеЛицо,
    ЛицевыеСчета.НомерЛицевогоСчета КАК НомерЛицевогоСчета,
    ЛицевыеСчета.Период КАК ДатаОткрытияСчета,
    ЕСТЬNULL(Склонения.РодительныйПадеж, "") КАК НаименованиеСотрудникаВРодПадеже,
    ВЫБОР
        КОГДА ФизЛица.Пол = ЗНАЧЕНИЕ(Перечисление.ПолФизическогоЛица.Мужской)
            ТОГДА 1
        ИНАЧЕ 2
    КОНЕЦ КАК Пол
ИЗ
    ВТ_ФизЛица КАК ВТ_ФизЛица
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ЛицевыеСчетаСотрудниковПоЗарплатнымПроектам.СрезПоследних(
        ,
    ) КАК ЛицевыеСчета
        ПО ВТ_ФизЛица.ФизическоеЛицо = ЛицевыеСчета.ФизическоеЛицо
    ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ФизическиеЛица КАК ФизЛица
        ПО ВТ_ФизЛица.ФизическоеЛицо = ФизЛица.Ссылка
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СклоненияПредставленийОбъектов КАК Склонения
        ПО ВТ_ФизЛица.ФизическоеЛицо = Склонения.Объект

Обратим внимание: обращение к реквизиту пола через точку заменено на явное соединение со справочником Справочник.ФизическиеЛица, что исключает появление неявных тяжелых соединений в плане запроса СУБД.

Рекомендуемый вариант 2: Передача массива физических лиц через параметры

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

Разберем пример реализации:


// 1. Получаем массив уникальных физических лиц
ЗапросФизЛиц = Новый Запрос;
ЗапросФизЛиц.Текст = 
    "ВЫБРАТЬ РАЗЛИЧНЫЕ
    |	Сотрудники.ФизическоеЛицо КАК ФизическоеЛицо
    |ИЗ
    |	Справочник.Сотрудники КАК Сотрудники
    |ГДЕ
    |	Сотрудники.Ссылка В(&МассивОбъектов)
    |	И Сотрудники.ФизическоеЛицо <> ЗНАЧЕНИЕ(Справочник.ФизическиеЛица.ПустаяСсылка)";

ЗапросФизЛиц.УстановитьПараметр("МассивОбъектов", МассивОбъектов);
МассивФизЛиц = ЗапросФизЛиц.Выполнить().Выгрузить().ВыгрузитьКолонку("ФизическоеЛицо");

// 2. Выполняем основной запрос с передачей массива в параметры среза
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ЛицевыеСчета.ФизическоеЛицо КАК ФизическоеЛицо,
    |	ЛицевыеСчета.НомерЛицевогоСчета КАК НомерЛицевогоСчета,
    |	ЛицевыеСчета.Период КАК ДатаОткрытияСчета
    |ИЗ
    |	РегистрСведений.ЛицевыеСчетаСотрудниковПоЗарплатнымПроектам.СрезПоследних(
    |			,
    |			ФизическоеЛицо В (&МассивФизЛиц)) КАК ЛицевыеСчета";

Запрос.УстановитьПараметр("МассивФизЛиц", МассивФизЛиц);
Результат = Запрос.Выполнить();

В данном сценарии условие транслируется в обычный список параметров SQL (IN (@P1, @P2, ...)), что позволяет СУБД оптимально задействовать индекс регистра без создания накладных расходов на создание и индексацию временных таблиц.

← На главную