Как создать таблицу значений со структурой табличной части документа

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке на платформе 1С:Предприятие часто возникает задача программного формирования таблицы значений (ТЗ), структура которой должна в точности повторять существующую табличную часть (ТЧ) какого-либо документа. Это особенно важно, когда предполагается дальнейшее использование этой таблицы в качестве параметра в запросе. Если колонки ТЗ не будут жестко типизированы, платформа может некорректно интерпретировать данные при создании временной таблицы в СУБД, что приведет к ошибкам или существенному снижению производительности. В этой статье мы подробно разберем несколько способов решения этой задачи, проанализируем их плюсы и минусы, а также изучим нюансы работы с типами данных.

Зачем нужна строгая типизация колонок?

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

  1. Анализирует типы колонок таблицы значений.
  2. Создает временную таблицу в базе данных SQL с соответствующими типами полей.
  3. Загружает данные из ТЗ в эту временную таблицу.

Если тип колонки в ТЗ не определен (имеет тип Произвольный), платформа пытается определить его по значению в первой строке. Если таблица пуста, это часто приводит к созданию поля типа NVARCHAR(1) или BINARY, что делает невозможным дальнейшее соединение этой таблицы с реальными данными БД или их индексацию. Поэтому типизация — это не просто "хороший тон", а техническая необходимость.

Способ 1: Использование метода ВыгрузитьКолонки() — "Золотой стандарт"

Рассмотрим наиболее элегантный и производительный способ, который часто встречается в типовых конфигурациях. Он заключается в использовании метода ВыгрузитьКолонки(). Для его реализации нам не нужно создавать реальный объект документа в памяти, достаточно обратиться к пустой ссылке.

Разберем пример кода:


// Получаем структуру колонок через пустую ссылку табличной части
ТЗ = Документы.РеализацияТоваровУслуг.ПустаяСсылка().Товары.ВыгрузитьКолонки();

Преимущества этого метода:

Важно помнить, что этот метод работает на сервере или в толстом клиенте. Если вам нужно получить структуру на стороне тонкого клиента, данные придется передавать с сервера.

Способ 2: Прямой перебор метаданных

Проанализируем ситуацию, когда нам нужно программно управлять процессом создания колонок, например, исключая определенные реквизиты или добавляя свои. В этом случае мы можем обратиться к объекту Метаданные.

Рассмотрим по шагам, как это реализовать:


ТЗ = Новый ТаблицаЗначений;
МетаданныеТЧ = Метаданные.Документы.РеализацияТоваровУслуг.ТабличныеЧасти.Товары;

// Перебираем реквизиты табличной части
Для Каждого Реквизит Из МетаданныеТЧ.Реквизиты Цикл
    ТЗ.Колонки.Добавить(Реквизит.Имя, Реквизит.Тип);
КонецЦикла;

Важное уточнение: При таком подходе мы упускаем так называемые "стандартные реквизиты", такие как НомерСтроки. Если ваша логика в запросе опирается на индекс строки, их нужно добавить отдельно, обратившись к коллекции СтандартныеРеквизиты того же объекта метаданных.

Способ 3: Использование пустого запроса

Довольно оригинальный и эффективный метод — получение структуры через результат запроса. Выясним, почему это удобно: запрос сразу возвращает объект ТаблицаЗначений с уже прописанными типами полей, которые максимально "понятны" для СУБД.

Пример реализации:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ ПЕРВЫЕ 0
    |   РеализацияТоваровУслугТовары.Номенклатура КАК Номенклатура,
    |   РеализацияТоваровУслугТовары.Количество КАК Количество,
    |   РеализацияТоваровУслугТовары.Цена КАК Цена
    |ИЗ
    |   Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары";

ТЗ = Запрос.Выполнить().Выгрузить();

Использование конструкции ВЫБРАТЬ ПЕРВЫЕ 0 гарантирует, что запрос не будет считывать данные из базы, а только сформирует схему результата. Этот метод хорош тем, что позволяет сразу задать псевдонимы полей (через КАК), которые могут отличаться от имен в метаданных.

Тонкости работы с типами для запросов

Разберем ситуацию с составными типами данных. Если в табличной части реквизит имеет составной тип (например, ДокументСсылка.Реализация, ДокументСсылка.Поступление), то при выгрузке в ТЗ и последующей передаче в запрос как временной таблицы, производительность соединений может упасть. SQL-серверу сложно индексировать поля с неопределенным типом.

Для оптимизации рекомендуется принудительно ограничивать тип в запросе, используя конструкцию ВЫРАЗИТЬ:


Запрос.Текст = 
    "ВЫБРАТЬ
    |   ВТ_Данные.Номенклатура,
    |   ВЫРАЗИТЬ(ВТ_Данные.ДокументОснование КАК Документ.РеализацияТоваровУслуг) КАК Ссылка
    |ИЗ
    |   &ВТ_Данные КАК ВТ_Данные";

Также стоит обратить внимание на строки неограниченной длины. Если в метаданных колонка ТЧ определена как строка неограниченной длины, вы не сможете проиндексировать ее во временной таблице. В таких случаях при создании колонок в ТЗ лучше вручную задать ОписаниеТипов с ограничением длины (например, 150-250 символов), если это допустимо бизнес-логикой.

Сводная таблица методов

Проанализируем и сравним все рассмотренные варианты:

  1. ВыгрузитьКолонки(): Рекомендуется для большинства задач. Минимум кода, высокая надежность.
  2. Цикл по Метаданным: Используется, когда нужна "хитрая" фильтрация колонок или их модификация на лету.
  3. Запрос (TOP 0): Идеален, когда вы хотите сразу переименовать колонки или отобрать только часть полей, используя синтаксис SQL.
  4. Создание объекта и Выгрузить(): (Упоминалось автором темы) — наименее предпочтительный вариант, так как создание целого объекта ДокументОбъект ради структуры — это лишний расход оперативной памяти.

В заключение отметим, что правильная типизация таблиц значений — это залог стабильной работы информационной системы. Выбирайте метод исходя из контекста задачи: для простого копирования структуры лучше ВыгрузитьКолонки(), для гибкой настройки — Запрос или Метаданные.

← На главную