В экосистеме 1С:Предприятие работа с данными часто требует гибкости, которую стандартные регистры или справочники не всегда могут обеспечить в моменте. Программисты сталкиваются с задачей обработки динамических наборов данных, которые существуют только в оперативной памяти во время выполнения кода. Для этих целей идеально подходит объект метаданных Таблица значений. Она позволяет формировать структуру «на лету», добавлять строки и колонки без создания лишних таблиц в базе данных.
Использование этого объекта критически важно при формировании сложных отчетов, где необходимо объединить данные из разных источников или выполнить промежуточные вычисления. Часто возникает потребность передать этот набор данных внутрь запроса для последующей фильтрации, сортировки или соединения с другими таблицами базы. Это превращает ТаблицуЗначений в мощный инструмент временного хранения, экономящий ресурсы СУБД.
В данной статье мы детально разберем механизмы создания, заполнения и, самое главное, правильного использования таблицы значений в качестве источника для запроса. Вы узнаете, как избежать типичных ошибок при маппинге типов данных и как оптимизировать производительность кода при работе с большими массивами информации в памяти.
Создание и инициализация структуры таблицы
Первым шагом всегда является объявление объекта. В коде на встроенном языке это делается через конструктор Новый ТаблицаЗначений(). Важно понимать, что при создании структура таблицы пуста — в ней нет ни колонок, ни строк. Программист должен явно определить схему данных, чтобы система понимала, какие типы значений будут храниться.
Для добавления колонок используется метод Колонки.Добавить(). Здесь необходимо указать имя колонки и тип значения. Ошибка в определении типа может привести к исключительной ситуации при попытке записать несовместимые данные. Например, если вы планируете хранить даты, тип должен быть строго Дата, а не Строка.
⚠️ Внимание: При добавлении колонок избегайте использования зарезервированных слов 1С или символов, недопустимых в именах полей SQL (например, пробелов или дефисов в начале имени), если планируете использовать таблицу в запросе. Это может вызвать ошибку компиляции запроса.
Рассмотрим пример создания структуры для хранения данных о номенклатуре и остатках. Мы создадим три колонки: ссылку на справочник, числовое количество и строковый комментарий.
ТабДанных = Новый ТаблицаЗначений();
ТабДанных.Колонки.Добавить("Номенклатура", Тип("СправочникСсылка.Номенклатура"));
ТабДанных.Колонки.Добавить("Количество", Тип("Число"));
ТабДанных.Колонки.Добавить("Примечание", Тип("Строка"));
Такой подход гарантирует типобезопасность. Если вы попытаетесь записать текст в колонку «Количество», платформа 1С сразу выдаст ошибку, что поможет отловить баги на раннем этапе. Кроме того, явное указание типов позволяет движку запросов оптимизировать выполнение.
Методы заполнения данными из различных источников
После определения структуры таблицу необходимо наполнить данными. Существует несколько способов сделать это, и выбор зависит от объема данных и их источника. Самый простой метод — построчное добавление через ТабДанных.Добавить(). Этот способ удобен для небольших наборов данных или когда строки формируются в цикле по результатам сложных вычислений.
Однако, если вам нужно скопировать данные из существующей выборки запроса или другой таблицы значений, использование цикла с методом Добавить() будет неэффективным. В таких случаях следует применять метод Загрузить(). Он позволяет массово перенести данные, сохраняя соответствие колонок по именам или индексам.
☑️ Алгоритм заполнения таблицы
При загрузке данных важно следить за соответствием имен колонок в источнике и приемнике. Если имена не совпадают, метод Загрузить() может не сработать корректно без дополнительных параметров маппинга. Также стоит учитывать, что при загрузке из запроса типы данных должны быть совместимы или приводимы.
- 📝 Используйте метод
Добавить()для ручного формирования отчетных строк с расчетными показателями. - 🚀 Применяйте
Загрузить()для быстрого переноса больших выборок из регистра сведений. - 🔄 Комбинируйте методы: сначала загрузите основу, затем добавьте расчетные колонки циклом.
Если данные поступают из внешнего источника, например, из JSON или XML, их сначала нужно распарсить в массив структур, а затем загрузить в таблицу значений. Это стандартный паттерн работы с внешними интеграциями в 1С.
Преобразование таблицы значений во временную таблицу запроса
Самый критичный момент в работе с этим объектом — передача его в контекст запроса. Объект ТаблицаЗначений существует только в памяти процесса 1С, тогда как запрос выполняется на стороне СУБД (или встроенного движка). Чтобы запрос «увидел» данные, таблицу нужно поместить в параметры запроса.
В тексте запроса такая таблица обозначается как &ИмяПараметра. Однако просто передать объект недостаточно. Необходимо, чтобы структура параметра совпадала с ожидаемой структурой временной таблицы в запросе. Система 1С автоматически создает временную таблицу в базе данных (или в памяти сервера), куда копирует содержимое вашего объекта.
⚠️ Внимание: Размер передаваемой таблицы значений влияет на производительность. Передача миллионов строк через параметр запроса может вызвать значительную нагрузку на сеть между клиентом и сервером 1С, а также на сервер баз данных при создании временной таблицы.
Рассмотрим синтаксис подключения. В коде вы создаете объект запроса, устанавливаете параметр и затем выполняете его. Важно именовать параметр так, как он указан в тексте запроса после знака амперсанда.
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ * ИЗ &ТаблицаКакИсточник КАК Источник";
Запрос.УстановитьПараметр("ТаблицаКакИсточник", ТабДанных);
Результат = Запрос.Выполнить();
Такой механизм позволяет использовать весь мощь языка запросов 1С (объединения, группировки, соединения) к данным, которых физически нет в конфигурации базы данных. Это открывает возможности для сложной аналитики «на лету».
Использование в операторах ВЫБРАТЬ и СОЕДИНИТЬ
Попав внутрь запроса, таблица значений ведет себя как обычная таблица базы данных. Вы можете выбирать из нее поля, накладывать условия отбора в секции ГДЕ и соединять с реальными таблицами конфигурации. Это особенно полезно для фильтрации больших списков документов по произвольному критерию, сформированному пользователем в интерфейсе.
Частый сценарий — использование таблицы значений как списка фильтров. Например, пользователь выбрал 50 контрагентов в форме отчета. Передавать их в запрос как 50 условий «ИЛИ» неэффективно. Проще создать таблицу значений с одним полем «Контрагент» и сделать ЛЕВОЕ СОЕДИНЕНИЕ или использовать оператор В.
Оптимизация соединений
При соединении таблицы значений с большой таблицей базы данных убедитесь, что по полям соединения в основной таблице установлены индексы. Хотя таблица значений временная, отсутствие индексов на стороне основной таблицы приведет к полному сканированию (table scan).
Пример использования в соединении для получения актуальных остатков только по выбранным товарам:
| Операция | Описание | Пример использования |
|---|---|---|
| ВЫБРАТЬ | Чтение данных из временной таблицы | ВЫБРАТЬ Номенклатура ИЗ &ТЗ |
| СОЕДИНИТЬ | Связь с регистром накопления | ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Остатки |
| ГДЕ | Фильтрация по полям таблицы | ГДЕ &ТЗ.ПометкаУдаления = ЛОЖЬ |
| УНИОН | Объединение с другим запросом | ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ... |
При использовании соединений важно следить за типами данных в условиях соединения. Если в таблице значений поле «Код» имеет тип Строка(10), а в справочнике — Строка(20), соединение все равно сработает, но неявное приведение типов может слегка замедлить выполнение.
Фильтрация и сортировка внутри запроса
Одним из главных преимуществ передачи таблицы значений в запрос является возможность использовать серверную сортировку и фильтрацию. Вместо того чтобы перебирать таблицу в цикле на уровне 1С (что медленно), вы делегируете эту задачу движку запросов.
Секция УПОРЯДОЧИТЬ ПО работает с временной таблицей так же эффективно, как и с обычной. Вы можете сортировать по нескольким полям, указывать направление сортировки (ASC/DESC). Это критично для формирования печатных форм и отчетов, где порядок строк имеет значение.
Если вам нужно отсортировать данные перед передачей в запрос (например, для специфической логики заполнения), используйте метод ТаблицаЗначений.Сортировать(). Но для финального вывода всегда предпочтительнее сортировка в запросе.
Фильтрация в секции ГДЕ позволяет отсеять лишние строки еще до того, как они попадут в результат выборки. Это уменьшает объем передаваемых данных обратно в приложение. Например, можно отобрать только те строки из переданной таблицы, где сумма больше определенного порога.
Пример сложной фильтрации с использованием вложенных запросов:
Вы можете выбрать из таблицы значений только те записи, которые имеют соответствия в регистре сведений. Это реализует логику «существования» (EXISTS) без явного цикла.
⚠️ Внимание: Избегайте использования функций, зависящих от контекста выполнения (например,
ТЕКУЩАЯДАТА()), внутри условий соединения с таблицей значений, если логика требует стабильности среза данных. Хотя для временных таблиц это менее критично, чем для регистров, единообразие подхода важно.
Очистка памяти и управление жизненным циклом
После выполнения запроса и обработки результатов объект ТаблицаЗначений, переданный как параметр, продолжает занимать оперативную память. В долгоживущих процессах или при частом вызове отчетов это может привести к росту потребления памяти сервером 1С.
Хотя сборщик мусора 1С автоматически освобождает память, когда ссылка на объект теряется, явная очистка больших временных структур считается хорошим тоном программирования. Особенно это актуально, если таблица значений использовалась как промежуточный буфер для импорта тяжелых файлов.
Для освобождения ресурсов достаточно присвоить переменной значение Неопределено или вызвать метод Очистить(), если планируется повторное использование объекта с той же структурой. Метод Очистить() удаляет строки, но оставляет структуру колонок, что может быть полезно для повторного заполнения.
Помните, что временная таблица, созданная движком запросов на стороне СУБД, уничтожается автоматически после завершения выполнения запроса или сессии. Вам не нужно писать SQL-команды DROP TABLE — платформа 1С берет это на себя.
Всегда проверяйте актуальность структуры таблицы значений перед передачей в запрос, если код изменялся. Добавление новой колонки в код 1С без обновления текста запроса приведет к ошибке выполнения.
Часто задаваемые вопросы (FAQ)
Можно ли передать таблицу значений в запрос, если она пустая?
Да, можно. Однако структура (колонки) должна быть определена. Если вы передадите пустую таблицу без колонок, запрос может выдать ошибку несоответствия метаданных. Пустая таблица с правильной структурой вернет пустой результат выборки.
Влияет ли размер таблицы значений на время компиляции запроса?
Нет, размер данных не влияет на компиляцию. Компиляция зависит от сложности текста запроса. Однако размер влияет на время выполнения и объем передаваемых данных между клиентом и сервером.
Как передать таблицу значений в хранимую процедуру на стороне SQL?
Напрямую передать объект 1С в нативную хранимую процедуру SQL нельзя. Необходимо сначала выгрузить данные во временную таблицу базы данных средствами 1С или использовать механизмы интеграции, специфичные для вашей СУБД.
Можно ли изменить структуру таблицы значений после передачи её в запрос?
Нет. После установки параметра и выполнения запроса изменение структуры исходной таблицы значений не повлияет на уже выполненную выборку. Для применения изменений нужно заново установить параметр и выполнить запрос.
Есть ли лимит на количество строк в таблице значений?
Технического жесткого лимита нет, он ограничен доступной оперативной памятью процесса 1С и настройками сервера. Однако при работе с сотнями тысяч строк рекомендуется использовать постраничную выборку или временные таблицы базы данных вместо таблиц значений в памяти.