Почему при выполнении запроса с оператором ПОМЕСТИТЬ возвращается только колонка Количество и как получить данные?

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

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

Разберем причину появления колонки «Количество»

Рассмотрим стандартное поведение платформы. Когда мы используем конструкцию ПОМЕСТИТЬ ИмяВременнойТаблицы, мы отдаем серверу баз данных команду не просто выбрать данные, а создать в специальном хранилище (в базе tempdb для MS SQL Server или аналогичных механизмах в других СУБД) структуру и заполнить ее результатом выборки.

Для платформы «1С» результатом такой операции является системное сообщение о количестве успешно обработанных строк. Если ваш запрос заканчивается оператором ПОМЕСТИТЬ, метод Выполнить() возвращает объект РезультатЗапроса, который по определению содержит только техническую информацию о созданной таблице. Это штатное поведение, документированное в синтакс-помощнике: результат выполнения инструкции по созданию временной таблицы — это число затронутых строк.

Проанализируем ситуацию на примере кода, похожего на тот, что вызвал вопрос:


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

Результат = Запрос.Выполнить();
Таблица = Результат.Выгрузить(); // Здесь мы получим колонку "Количество"

Способ 1: Использование завершающего запроса ВЫБРАТЬ

Самый простой и «классический» способ получить данные из временной таблицы — это добавить в текст запроса еще одну секцию, которая будет выбирать данные из только что созданной ВТ. В этом случае метод Выполнить() вернет результат именно последнего запроса в пакете.

Давайте изменим наш текст запроса, чтобы увидеть разницу:


Запрос.Текст = 
    "ВЫБРАТЬ ... ПОМЕСТИТЬ ВТ_Данные ИЗ ... ;
    |ВЫБРАТЬ * ИЗ ВТ_Данные"; // Добавляем выборку из временной таблицы

Теперь Запрос.Выполнить().Выгрузить() вернет нам полноценную таблицу значений со всеми полями, которые мы определили в первой части пакета. Этот метод универсален и работает на всех версиях платформы 8.х.

Способ 2: Метод ВыполнитьПакет()

Если нам нужно не только получить финальные данные, но и знать, сколько строк попало в промежуточные таблицы, или если пакет содержит несколько независимых выборок, целесообразно использовать метод ВыполнитьПакет(). Этот метод возвращает массив объектов РезультатЗапроса.

Рассмотрим, как это работает по шагам:

  1. Каждый запрос в тексте, разделенный символом «точка с запятой» (;), формирует отдельный элемент в результирующем массиве.
  2. Если запрос содержал ПОМЕСТИТЬ, соответствующий ему элемент массива будет содержать ту самую колонку Количество.
  3. Если запрос содержал обычный ВЫБРАТЬ, элемент массива будет содержать данные.

Пример обработки пакета:


МассивРезультатов = Запрос.ВыполнитьПакет();
// Результат первого запроса (с ПОМЕСТИТЬ)
КоличествоЗаписей = МассивРезультатов[0].Выгрузить()[0].Количество;
// Результат второго запроса (ВЫБРАТЬ)
ДанныеТаблицы = МассивРезультатов[1].Выгрузить();

Способ 3: Метод ВыполнитьПакетСПромежуточнымиДанными()

Начиная с версии платформы 8.3.10, разработчикам стал доступен более мощный инструмент — ВыполнитьПакетСПромежуточнымиДанными(). Проанализируем его преимущество: этот метод заставляет платформу игнорировать стандартное поведение оператора ПОМЕСТИТЬ в плане возврата только количества строк.

При использовании этого метода массив результатов будет содержать полные выборки данных для каждой временной таблицы, даже если вы не писали явный ВЫБРАТЬ в конце пакета. Это крайне удобно для отладки сложных запросов или когда временная таблица нужна в коде 1С для дальнейшей обработки программными методами.

Важные нюансы: ИМЕЮЩИЕ и пустые таблицы

Выясним причину, по которой временная таблица может оказаться пустой (значение «0» в колонке Количество). В исходном запросе автора используется условие ИМЕЮЩИЕ СУММА(СтраховыеВзносыСведенияОДоходах.Сумма) < 0.

Обратите внимание: если после группировки данных ни одна строка не удовлетворяет условию секции ИМЕЮЩИЕ, временная таблица будет создана, но она будет пустой. В этом случае метод Выполнить() честно вернет «0». Это не ошибка платформы, а результат логики вашего запроса. Если вы ожидаете данные, но получаете 0, стоит проверить входящие данные или условия фильтрации ГДЕ и ИМЕЮЩИЕ.

Оптимизация работы с временными таблицами

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

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


|ПОМЕСТИТЬ ВТЗаписиЗаПрошлыйПериод
|ИЗ
|   ...
|ИНДЕКСИРОВАТЬ ПО
|   ФизическоеЛицо,
|   ВидДохода

Без явного указания ИНДЕКСИРОВАТЬ ПО СУБД может выбрать неоптимальный план выполнения (например, Nested Loops вместо Hash Match), что приведет к существенным задержкам на больших объемах данных, характерных для учета страховых взносов.

Итоги

Подводя итог, можно сказать, что появление колонки Количество — это сигнал о том, что последней операцией в вашем запросе было создание временной таблицы. Чтобы получить данные:

← На главную