В разработке на платформе 1С:Предприятие 8․3 таблица значений (ТаблицаЗначений) является одним из самых универсальных и часто используемых объектов для хранения и обработки временных наборов данных в памяти․ Умение эффективно взаимодействовать с ней через язык запросов, ключевой навык для написания производительного и чистого кода․ В этой статье подробно разберем, как передать таблицу значений в запрос как параметр, как получить данные запроса в таблицу значений, а также рассмотрим продвинутые техники работы с временными таблицами․
Передача таблицы значений в запрос как параметра
Согласно документации 1С:ИТС и лучшим практикам разработки, передача таблицы значений в запрос позволяет избежать выполнения запросов в цикле, что критически важно для производительности․ Вместо множественных обращений к СУБД мы формируем набор данных на клиенте (или сервере) один раз и передаем его целиком․
Подготовка таблицы значений
Перед передачей в запрос таблица значений должна иметь определенную структуру: колонки, соответствующие полям, которые будут использоваться в запросе (в условиях соединения ВНУТРЕННЕЕ СОЕДИНЕНИЕ, в условии ГДЕ с оператором В и т․д․)․
// Пример формирования таблицы значений
ТзНоменклатура = Новый ТаблицаЗначений;
ТзНоменклатура․Колонки․Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка․Номенклатура"));
ТзНоменклатура․Колонки․Добавить("Количество", Новый ОписаниеТипов("Число", 15, 3));
// Заполнение данными
СтрокаТз = ТзНоменклатура․Добавить;
СтрокаТз․Номенклатура = Справочники․Номенклатура․НайтиПоНаименованию("Товар 1");
СтрокаТз․Количество = 10;
// ․․․ добавление остальных строк
Установка параметра запроса
Для передачи используется метод УстановитьПараметр объекта Запрос․ Имя параметра в тексте запроса должно совпадать с именем, переданным в метод․
Запрос = Новый Запрос;
Запрос․Текст =
"ВЫБРАТЬ
| Тз․Номенклатура КАК Номенклатура,
| Тз․Количество КАК Количество,
| ЦеныНоменклатуры․Цена КАК Цена
|ИЗ
| &ТаблицаНоменклатуры КАК Тз
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений․ЦеныНоменклатуры КАК ЦеныНоменклатуры
| ПО Тз․Номенклатура = ЦеныНоменклатуры․Номенклатура";
Запрос․УстановитьПараметр("ТаблицаНоменклатуры", ТзНоменклатура);
Результат = Запрос․Выполнить;
Важно: Платформа автоматически создает временную таблицу в базе данных, загружает в нее данные из переданной
ТаблицаЗначенийи использует в запросе․ Типы данных колонок временной таблицы определяются на основе типов значений в колонкахТаблицаЗначений․ Рекомендуется явно задавать типы колонок черезОписаниеТиповдля избежания ошибок несовместимости типов при соединении с полями таблиц БД․
Получение результата запроса в таблицу значений
После выполнения запроса результат можно загрузить в ТаблицаЗначений несколькими способами в зависимости от задачи․
Метод Выгрузить — классический способ
Метод Выгрузить объекта РезультатЗапроса создает новую таблицу значений и заполняет её данными выборки․ Это самый простой способ получить полную копию данных результата запроса․
РезультатЗапроса = Запрос․Выполнить;
ТаблицаРезультата = РезультатЗапроса․Выгрузить; // Возвращает ТаблицаЗначений
// Работа с полученной таблицей
Для Каждого Строка Из ТаблицаРезультата Цикл
Сообщить(Строка․Номенклатура + ": " + Строка․Цена);
КонецЦикла;
Метод Выбрать — итеративное чтение (для экономии памяти)
Если результат запроса очень велик (десятки/сотни тысяч строк), выгрузка всей таблицы в память может привести к переполнению оперативной памяти․ В таких случаях используется поточная обработка через объект ВыборкаИзРезультатаЗапроса․
Выборка = РезультатЗапроса․Выбрать;
Пока Выборка․Следующий Цикл
// Обработка каждой строки без загрузки всего массива в память
ОбработатьСтрокуРезультата(Выборка․Номенклатура, Выборка․Цена);
КонецЦикла;
Загрузка в существующую таблицу значений (Load/Загрузить)
Начине с недавних версий платформы (и в управляемых формах), для заполнения уже существующей таблицы значений (например, табличной части документа или формы) удобно использовать метод Загрузить у самой таблицы значений, передав ей выборку или результат запроса․
// Пример загрузки в табличную часть документа
ДокументОбъект․Товары․Загрузить(РезультатЗапроса); // Прямая загрузка из результата запроса
// Или через выборку для больших объемов
Выборка = РезультатЗапроса․Выбрать;
ДокументОбъект․Товары․Загрузить(Выборка);
При этом происходит автоматическое сопоставление колонок по именам; Если имена колонок в запросе и в таблице значений отличаются, можно использовать параметр СоответствиеКолонок (структура или массив пар)․
Использование таблицы значений как источника временной таблицы
Как описано в официальной документации 1С:ИТС, при передаче таблицы значений в параметр запроса платформа неявно создает временную таблицу на уровне СУБД․ Это важный механизм, понимая который можно писать более сложные и быстрые запросы․
Особенности временных таблиц:
- Жизненный цикл: Временная таблица существует в рамках текущего соединения с базой данных (сеанса)․ Она автоматически удаляется при завершении выполнения запроса или сеанса․
- Индексы: Платформа может автоматически создавать индексы по полям, участвующим в условиях соединения (
СОЕДИНЕНИЕ) или отбора (ГДЕ), что ускоряет выполнение․ - Ограничения: Нельзя ссылаться на временную таблицу, созданную из параметра, в других запросах, выполняемых отдельно (в другом объекте
Запрос), если только не используется пакетный запрос или управляемые блокировки․
Пример сложного запроса с использованием переданной таблицы
Частая задача — получить остатки по списку номенклатуры из таблицы значений сразу по нескольким складам и видам цен․
Запрос․Текст =
"ВЫБРАТЬ
| Тз․Номенклатура КАК Номенклатура,
| Тз․Склад КАК Склад,
| ЕСТЬNULL(Остатки․КоличествоОстаток, 0) КАК Остаток,
| Цены․Цена КАК Цена
|ИЗ
| &ПараметрыОтбора КАК Тз
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления․ОстаткиТоваров․Остатки(&МоментВремени, Номенклатура В ВЫБРАТЬ Номенклатура ИЗ &ПараметрыОтбора) КАК Остатки
| ПО Тз․Номенклатура = Остатки․Номенклатура И Тз․Склад = Остатки․Склад
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений․ЦеныНоменклатуры․СрезПоследних(&МоментВремени, Номенклатура В ВЫБРАТЬ Номенклатура ИЗ &ПараметрыОтбора) КАК Цены
| ПО Тз․Номенклатура = Цены․Номенклатура";
Запрос․УстановитьПараметр("ПараметрыОтбора", ТзПараметры); // ТаблицаЗначений с колонками Номенклатура, Склад
Запрос․УстановитьПараметр("МоментВремени", ТекущаяДата);
Типичные ошибки и лучшие практики
Несовпадение типов данных
Самая частая ошибка — передача таблицы значений с колонками типа Строка или Число без точности, когда запрос ожидает ссылку на справочник или число с фиксированной точностью․
- Решение: Всегда явно задавайте типы колонок при создании таблицы значений:
Тз․Колонки․Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка․Номенклатура"));․
Передача пустой таблицы значений
Если передать пустую таблицу значений (без строк), платформа все равно создаст временную таблицу, но в ней не будет данных․ Соединение (JOIN) с пустой таблицей вернет пустой результат․ Это корректное поведение, но если логика подразумевает «если список пуст — выбрать все», нужно добавлять проверку в коде 1С и менять текст запроса (убирать условие соединения/отбора)․
Производительность при больших объемах
- Передача таблицы значений с десятками тысяч строк в параметр запроса может занять заметное время на сериализацию и загрузку во временную таблицу СУБД․
- Для очень больших наборов данных (сотни тысяч строк и более) иногда эффективнее записать данные во временную таблицу самостоятельно через
ВРЕМЕННАЯ ТАБЛИЦАв тексте пакетного запроса или использовать регистр накопления/сведений как промежуточное хранилище․
Использование оператора В (IN) вместо СОЕДИНЕНИЯ
Для небольших списков (до нескольких сотен значений) можно передать массив значений и использовать оператор В:
ГДЕ Номенклатура В &МассивНоменклатуры․
Однако для таблиц значений с множеством колонок или большим количеством строк ВНУТРЕННЕЕ СОЕДИНЕНИЕ (INNER JOIN) с переданной таблицей значений почти всегда работает быстрее и корректнее обрабатывает NULL-значения․
Резюме: алгоритм работы
- Сформируйте
ТаблицаЗначенийс нужными колонками и явно заданными типами (ОписаниеТипов)․ - Заполните её данными (из формы, другого запроса, файла и т․д․)․
- Создайте объект
Запрос, в тексте используйте имя параметра (например,&МояТаблица) как имя таблицы в секцииИЗилиСОЕДИНЕНИЕ․ - Установите параметр:
Запрос․УстановитьПараметр("МояТаблица", ТзДанные);․ - Выполните запрос:
Результат = Запрос․Выполнить;․ - Получите данные:
ТзРезультат = Результат․Выгрузить;— для небольших/средних выборок․Выборка = Результат․Выбрать;— для больших выборок (поточная обработка)․ТабличнаяЧасть․Загрузить(Результат);— для прямого заполнения объектов метаданных․
Грамотное использование таблиц значений в запросах — это фундамент производительных алгоритмов в 1С․ Оно позволяет перенести логику фильтрации и агрегации на сторону СУБД, минимизируя сетевой трафик и нагрузку на кластер 1С․