Работа с таблицами значений (ТЗ) — это повседневная задача любого разработчика 1С. Однако иногда стандартных методов перебора строк становится недостаточно, особенно когда требуется выполнить сложную группировку, агрегацию данных или соединение временных данных с реальными таблицами базы данных. В таких случаях на помощь приходит механизм запросов к таблицам значений. Несмотря на удобство, этот метод таит в себе множество подводных камней, начиная от особенностей работы управляемых форм и заканчивая нюансами типизации колонок.
В этой статье мы подробно разберем, как правильно передать таблицу значений в запрос, почему возникают стандартные ошибки и как их эффективно обойти.
Рассмотрим ситуацию, когда у нас уже есть заполненная таблица значений и нам нужно сгруппировать данные по какому-либо полю (например, по сотруднику), чтобы посчитать количество вхождений. Основная идея заключается в том, чтобы передать ТЗ в качестве параметра запроса и поместить ее во временную таблицу.
Шаг 1: Подготовка таблицы значений и типизация
Первое и самое важное правило: колонки таблицы значений должны быть строго типизированы. Если вы создаете таблицу динамически, обязательно указывайте ОписаниеТипов. Если типы не заданы или колонка содержит значения неограниченной длины (например, длинную строку), запрос выдаст ошибку или откажется выполнять группировку.
// Правильное создание ТЗ с типизацией
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("СправочникСсылка.Сотрудники"));
ОписаниеТиповСотрудник = Новый ОписаниеТипов(МассивТипов);
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Сотрудник", ОписаниеТиповСотрудник);
ТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
Шаг 2: Особенности управляемых форм
Проанализируем частую ошибку начинающих разработчиков. В управляемом приложении реквизит формы с типом Таблица значений на самом деле является объектом типа ДанныеФормыКоллекция. Этот объект нельзя напрямую передать в запрос. Чтобы запрос "увидел" таблицу, ее нужно конвертировать в "честную" таблицу значений.
Используем метод Выгрузить() для получения реального объекта ТЗ:
// Если "Список" — это реквизит формы (таблица на экране)
ТаблицаДляЗапроса = Объект.Список.Выгрузить();
Шаг 3: Инициализация Менеджера временных таблиц
Выясним, почему возникает ошибка "Не установлен менеджер временных таблиц". Запрос к внешней таблице значений всегда требует создания временной таблицы в оперативной памяти (или в СУБД). Чтобы платформа знала, где хранить эти данные между выполнениями различных частей запроса, необходимо явно инициализировать МенеджерВременныхТаблиц.
Шаг 4: Написание кода запроса
Рассмотрим полный цикл выполнения запроса к таблице значений:
Функция СчитатьДанныеТЗ(ИсходнаяТЗ) Экспорт
Запрос = Новый Запрос;
// Обязательно создаем менеджер временных таблиц
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
// Текст первого запроса: помещаем ТЗ во временную таблицу
Запрос.Текст =
"ВЫБРАТЬ
| ВнешняяТЗ.Сотрудник КАК Сотрудник,
| ВнешняяТЗ.Количество КАК Количество
|ПОМЕСТИТЬ ВТ_Данные
|ИЗ
| &ВнешняяТЗ КАК ВнешняяТЗ";
// Устанавливаем параметр (выгруженную таблицу значений)
Запрос.УстановитьПараметр("ВнешняяТЗ", ИсходнаяТЗ);
// Выполняем первую часть, чтобы данные попали в менеджер
Запрос.Выполнить();
// Теперь можно работать с ВТ_Данные как с обычной таблицей базы
Запрос.Текст =
"ВЫБРАТЬ
| ВТ_Данные.Сотрудник КАК Сотрудник,
| СУММА(ВТ_Данные.Количество) КАК ОбщееКоличество
|ИЗ
| ВТ_Данные КАК ВТ_Данные
|ГРУППИРОВАТЬ ПО
| ВТ_Данные.Сотрудник";
Результат = Запрос.Выполнить();
Возврат Результат.Выгрузить();
КонецФункции
Часто программисты сталкиваются с ошибкой: "Недопустимое поле для группировки". Проанализируем причину. В 1С строки бывают двух видов: ограниченной длины (например, Строка(100)) и неограниченной длины. SQL-сервер не может эффективно индексировать и сравнивать поля неограниченной длины в операциях СГРУППИРОВАТЬ ПО.
Как исправить: при создании колонок в ТЗ всегда указывайте квалификаторы строк. Если данные уже в таблице и они "неограниченные", в самом запросе можно попробовать использовать функцию ВЫРАЗИТЬ(Поле КАК СТРОКА(255)), но лучше всего типизировать саму ТЗ перед передачей в параметр.
Нужно ли всегда использовать запрос? Вовсе нет. Рассмотрим ситуацию, когда нам нужно просто свернуть таблицу и посчитать количество строк. Метод Свернуть() работает значительно быстрее, так как выполняется целиком в оперативной памяти сервера 1С и не требует накладных расходов на передачу данных в СУБД и создание временных таблиц.
Посмотрим на пример реализации агрегации через методы объекта ТаблицаЗначений:
// Предположим, у нас есть ТЗ с колонками "Сотрудник", "Отдел"
// Мы хотим получить уникальный список сотрудников и количество их записей
ТЗ_Копия = ИсходнаяТЗ.Скопировать();
ТЗ_Копия.Колонки.Добавить("Счетчик", Новый ОписаниеТипов("Число"));
ТЗ_Копия.ЗаполнитьЗначения(1, "Счетчик");
// Группируем данные: первый параметр — поля группировки, второй — агрегируемые поля
ТЗ_Копия.Свернуть("Сотрудник", "Счетчик");
// Теперь в колонке "Счетчик" у каждого уникального сотрудника будет сумма единиц
Для Каждого Стр Из ТЗ_Копия Цикл
Сообщить("Сотрудник: " + Стр.Сотрудник + " - Записей: " + Стр.Счетчик);
КонецЦикла;
Проанализируем, какой подход лучше выбрать в зависимости от условий задачи:
ЛЕВОЕ СОЕДИНЕНИЕ) данные из вашей таблицы с данными из базы (например, со справочником Номенклатура или остатками на регистрах).НайтиСтроки(), обязательно добавьте индекс: ТЗ.Индексы.Добавить("Сотрудник"). Это в разы ускорит работу на больших объемах данных.Рассмотрим ситуацию с большими таблицами. Если в вашей ТЗ более 50-100 тысяч строк, передача ее в запрос может вызвать существенную задержку. Платформа физически записывает эти данные во временную таблицу базы данных. В таких случаях мы рекомендуем пересмотреть архитектуру: возможно, стоит изначально получать данные запросом из базы, а не собирать их в таблицу в коде 1С.
Также помните, что имена колонок в ТЗ должны соответствовать правилам именования переменных: никаких пробелов, точек и спецсимволов. В противном случае синтаксический анализатор запроса выдаст ошибку еще на этапе компиляции.
Таким образом, мы выяснили, что работа с ТЗ через запрос — это мощный инструмент, требующий однако аккуратности в типизации и понимания контекста выполнения кода (Сервер/Клиент). Соблюдение этих простых правил позволит вам писать стабильный и быстрый код.