Работа с таблицей значений в запросах 1С: передача параметром и получение результата

Освойте передачу ТаблицаЗначений в запрос и обратную выгрузку данных. Пишите чистый, быстрый код на 1С:Предприятие 8.3 без лишних циклов!

Бесплатная консультация юриста

+7 (800) 301-07-30

Реклама jurik.ru

В разработке на платформе 1С:Предприятие 8․3 таблица значений (ТаблицаЗначений) является одним из самых универсальных и часто используемых объектов для хранения и обработки временных наборов данных в памяти․ Умение эффективно взаимодействовать с ней через язык запросов, ключевой навык для написания производительного и чистого кода․ В этой статье подробно разберем, как передать таблицу значений в запрос как параметр, как получить данные запроса в таблицу значений, а также рассмотрим продвинутые техники работы с временными таблицами․

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

Согласно документации 1С:ИТС и лучшим практикам разработки, передача таблицы значений в запрос позволяет избежать выполнения запросов в цикле, что критически важно для производительности․ Вместо множественных обращений к СУБД мы формируем набор данных на клиенте (или сервере) один раз и передаем его целиком․

Подготовка таблицы значений

Перед передачей в запрос таблица значений должна иметь определенную структуру: колонки, соответствующие полям, которые будут использоваться в запросе (в условиях соединения ВНУТРЕННЕЕ СОЕДИНЕНИЕ, в условии ГДЕ с оператором В и т․д․)․

// Пример формирования таблицы значений
ТзНоменклатура = Новый ТаблицаЗначений;
ТзНоменклатура․Колонки․Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка․Номенклатура"));
ТзНоменклатура․Колонки․Добавить("Количество", Новый ОписаниеТипов("Число", 15, 3));

// Заполнение данными
СтрокаТз = ТзНоменклатура․Добавить;
СтрокаТз․Номенклатура = Справочники․Номенклатура․НайтиПоНаименованию("Товар 1");
СтрокаТз․Количество = 10;
// ․․․ добавление остальных строк

Установка параметра запроса

Для передачи используется метод УстановитьПараметр объекта Запрос․ Имя параметра в тексте запроса должно совпадать с именем, переданным в метод․

Запрос = Новый Запрос;
Запрос․Текст = 
	"ВЫБРАТЬ
	|	Тз․Номенклатура КАК Номенклатура,
	|	Тз․Количество КАК Количество,
	|	ЦеныНоменклатуры․Цена КАК Цена
	|ИЗ
	|	&ТаблицаНоменклатуры КАК Тз
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений․ЦеныНоменклатуры КАК ЦеныНоменклатуры
	|		ПО Тз․Номенклатура = ЦеныНоменклатуры․Номенклатура";

Запрос․УстановитьПараметр("ТаблицаНоменклатуры", ТзНоменклатура);
Результат = Запрос․Выполнить;

Важно: Платформа автоматически создает временную таблицу в базе данных, загружает в нее данные из переданной ТаблицаЗначений и использует в запросе․ Типы данных колонок временной таблицы определяются на основе типов значений в колонках ТаблицаЗначений․ Рекомендуется явно задавать типы колонок через ОписаниеТипов для избежания ошибок несовместимости типов при соединении с полями таблиц БД․

Получение результата запроса в таблицу значений

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

Метод Выгрузить — классический способ

Метод Выгрузить объекта РезультатЗапроса создает новую таблицу значений и заполняет её данными выборки․ Это самый простой способ получить полную копию данных результата запроса․

РезультатЗапроса = Запрос․Выполнить;
ТаблицаРезультата = РезультатЗапроса․Выгрузить; // Возвращает ТаблицаЗначений

// Работа с полученной таблицей
Для Каждого Строка Из ТаблицаРезультата Цикл
	Сообщить(Строка․Номенклатура + ": " + Строка․Цена);
КонецЦикла;

Метод Выбрать — итеративное чтение (для экономии памяти)

Если результат запроса очень велик (десятки/сотни тысяч строк), выгрузка всей таблицы в память может привести к переполнению оперативной памяти․ В таких случаях используется поточная обработка через объект ВыборкаИзРезультатаЗапроса․

Выборка = РезультатЗапроса․Выбрать;
Пока Выборка․Следующий Цикл
	// Обработка каждой строки без загрузки всего массива в память
	ОбработатьСтрокуРезультата(Выборка․Номенклатура, Выборка․Цена);
КонецЦикла;

Загрузка в существующую таблицу значений (Load/Загрузить)

Начине с недавних версий платформы (и в управляемых формах), для заполнения уже существующей таблицы значений (например, табличной части документа или формы) удобно использовать метод Загрузить у самой таблицы значений, передав ей выборку или результат запроса․

// Пример загрузки в табличную часть документа
ДокументОбъект․Товары․Загрузить(РезультатЗапроса); // Прямая загрузка из результата запроса

// Или через выборку для больших объемов
Выборка = РезультатЗапроса․Выбрать;
ДокументОбъект․Товары․Загрузить(Выборка);

При этом происходит автоматическое сопоставление колонок по именам; Если имена колонок в запросе и в таблице значений отличаются, можно использовать параметр СоответствиеКолонок (структура или массив пар)․

Использование таблицы значений как источника временной таблицы

Как описано в официальной документации 1С:ИТС, при передаче таблицы значений в параметр запроса платформа неявно создает временную таблицу на уровне СУБД․ Это важный механизм, понимая который можно писать более сложные и быстрые запросы․

Особенности временных таблиц:

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

Пример сложного запроса с использованием переданной таблицы

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

Запрос․Текст = 
	"ВЫБРАТЬ
	|	Тз․Номенклатура КАК Номенклатура,
	|	Тз․Склад КАК Склад,
	|	ЕСТЬNULL(Остатки․КоличествоОстаток, 0) КАК Остаток,
	|	Цены․Цена КАК Цена
	|ИЗ
	|	&ПараметрыОтбора КАК Тз
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления․ОстаткиТоваров․Остатки(&МоментВремени, Номенклатура В ВЫБРАТЬ Номенклатура ИЗ &ПараметрыОтбора) КАК Остатки
	|		ПО Тз․Номенклатура = Остатки․Номенклатура И Тз․Склад = Остатки․Склад

	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений․ЦеныНоменклатуры․СрезПоследних(&МоментВремени, Номенклатура В ВЫБРАТЬ Номенклатура ИЗ &ПараметрыОтбора) КАК Цены
	|	ПО Тз․Номенклатура = Цены․Номенклатура";

Запрос․УстановитьПараметр("ПараметрыОтбора", ТзПараметры); // ТаблицаЗначений с колонками Номенклатура, Склад
Запрос․УстановитьПараметр("МоментВремени", ТекущаяДата);

Типичные ошибки и лучшие практики

Несовпадение типов данных

Самая частая ошибка — передача таблицы значений с колонками типа Строка или Число без точности, когда запрос ожидает ссылку на справочник или число с фиксированной точностью․

  • Решение: Всегда явно задавайте типы колонок при создании таблицы значений: Тз․Колонки․Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка․Номенклатура"));․

Передача пустой таблицы значений

Если передать пустую таблицу значений (без строк), платформа все равно создаст временную таблицу, но в ней не будет данных․ Соединение (JOIN) с пустой таблицей вернет пустой результат․ Это корректное поведение, но если логика подразумевает «если список пуст — выбрать все», нужно добавлять проверку в коде 1С и менять текст запроса (убирать условие соединения/отбора)․

Производительность при больших объемах

  • Передача таблицы значений с десятками тысяч строк в параметр запроса может занять заметное время на сериализацию и загрузку во временную таблицу СУБД․
  • Для очень больших наборов данных (сотни тысяч строк и более) иногда эффективнее записать данные во временную таблицу самостоятельно через ВРЕМЕННАЯ ТАБЛИЦА в тексте пакетного запроса или использовать регистр накопления/сведений как промежуточное хранилище․

Использование оператора В (IN) вместо СОЕДИНЕНИЯ

Для небольших списков (до нескольких сотен значений) можно передать массив значений и использовать оператор В:
ГДЕ Номенклатура В &МассивНоменклатуры․
Однако для таблиц значений с множеством колонок или большим количеством строк ВНУТРЕННЕЕ СОЕДИНЕНИЕ (INNER JOIN) с переданной таблицей значений почти всегда работает быстрее и корректнее обрабатывает NULL-значения․

Резюме: алгоритм работы

  1. Сформируйте ТаблицаЗначений с нужными колонками и явно заданными типами (ОписаниеТипов)․
  2. Заполните её данными (из формы, другого запроса, файла и т․д․)․
  3. Создайте объект Запрос, в тексте используйте имя параметра (например, &МояТаблица) как имя таблицы в секции ИЗ или СОЕДИНЕНИЕ․
  4. Установите параметр: Запрос․УстановитьПараметр("МояТаблица", ТзДанные);․
  5. Выполните запрос: Результат = Запрос․Выполнить;․
  6. Получите данные:
    • ТзРезультат = Результат․Выгрузить; — для небольших/средних выборок․
    • Выборка = Результат․Выбрать; — для больших выборок (поточная обработка)․
    • ТабличнаяЧасть․Загрузить(Результат); — для прямого заполнения объектов метаданных․

Грамотное использование таблиц значений в запросах — это фундамент производительных алгоритмов в 1С․ Оно позволяет перенести логику фильтрации и агрегации на сторону СУБД, минимизируя сетевой трафик и нагрузку на кластер 1С․