Как правильно типизировать колонки Таблицы Значений для субконто и работы в запросах

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

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

Почему стандартный метод ТипВсеСсылки() не подходит для запросов

Проанализируем типичную ошибку начинающих разработчиков. Часто предпринимаются попытки собрать все возможные типы ссылок в один массив и создать на его основе ОписаниеТипов. Рассмотрим пример такого кода:


СписокТипов = Новый Массив;
СписокТипов.Добавить(Документы.ТипВсеСсылки());
СписокТипов.Добавить(Справочники.ТипВсеСсылки());
СписокТипов.Добавить(Перечисления.ТипВсеСсылки());
ОписаниеСоставногоТипа = Новый ОписаниеТипов(СписокТипов);
ТЗ.Колонки.Добавить("Субконто1", ОписаниеСоставногоТипа);

При попытке передать такую таблицу в запрос как параметр и выполнить конструкцию ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Данные ИЗ &ТЗ КАК ТЗ, платформа 1С выдаст ошибку. Выясним причину: когда ТЗ помещается во временную таблицу, система пытается создать в базе данных SQL реальную таблицу. Для каждой ссылки в составном типе SQL-серверу необходимо создать набор полей. Если мы указываем «все ссылки», количество типов может превысить системные лимиты СУБД на количество колонок в таблице. Именно поэтому составной тип в запросе должен быть строго ограничен.

Решение 1: Использование метаданных Плана Видов Характеристик

Самый правильный и надежный способ — использовать уже готовое описание типов, которое заложено в метаданных вашего плана счетов. В типовых конфигурациях типы всех возможных субконто уже определены в соответствующем Плане Видов Характеристик (ПВХ). Рассмотрим, как программно получить этот тип и применить его к колонке ТЗ.


// Получаем описание типов из метаданных ПВХ
ТипСубконто = Метаданные.ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Тип;

ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Субконто1", ТипСубконто);
ТЗ.Колонки.Добавить("Субконто2", ТипСубконто);
ТЗ.Колонки.Добавить("Субконто3", ТипСубконто);

Этот метод хорош тем, что ОписаниеТипов, взятое из метаданных, уже оптимизировано платформой. Оно содержит только те типы, которые реально могут выступать в роли аналитики на счетах учета, и не перегружает структуру запроса лишними данными.

Решение 2: Динамическое создание ОписанияТипов через конструктор

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


// Сначала создаем базовое описание (например, для всех справочников)
Описание = Справочники.ТипВсеСсылки();

// Теперь расширяем его типами документов
Описание = Новый ОписаниеТипов(Описание, Документы.ТипВсеСсылки().Типы());

// Создаем колонку с итоговым описанием
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("ОбъектВыгрузки", Описание);

Обратите внимание на использование второго параметра в конструкторе Новый ОписаниеТипов. Мы передаем исходное описание и массив добавляемых типов. Это позволяет системе корректно «схлопнуть» типы в единый массив, который будет понятен менеджеру временных таблиц.

Решение 3: Вариант для ленивых через пустой запрос

Существует еще один изящный способ получить идеально типизированную таблицу значений без обращения к метаданным вручную. Мы можем попросить сам движок запросов сформировать нам нужную структуру. Разберем этот пример:


ТекстЗапроса = "ВЫБРАТЬ ПЕРВЫЕ 0
               |    Значение КАК Субконто1,
               |    Значение КАК Субконто2,
               |    Значение КАК Субконто3
               |ИЗ
               |    РегистрБухгалтерии.Хозрасчетный.Субконто";

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

В данном случае мы обращаемся к виртуальной таблице или таблице значений субконто регистра бухгалтерии. Поле Значение там уже имеет необходимый составной тип. Выгрузив результат запроса с условием ПЕРВЫЕ 0, мы получаем пустую ТЗ с уже готовыми, идеально типизированными колонками, которые гарантированно «проглотятся» любым последующим запросом.

Работа с NULL и проблемы соединения таблиц

При работе с составными типами и типизированными ТЗ часто возникает вопрос обработки значений NULL. Если вы планируете использовать полученную ТЗ в запросе для соединения (JOIN) с другими таблицами, нужно учитывать следующие моменты:

  1. Значение по умолчанию: В типизированной колонке ТЗ по умолчанию содержится Неопределено (для ссылочных типов). В запросе это значение будет интерпретироваться корректно, если тип колонки совпадает с типом поля источника.
  2. Сравнение на NULL: Помните, что в языке запросов 1С условие ТЗ.Субконто1 = Источник.Субконто1 вернет Ложь, если в обоих полях содержится NULL. Проанализируем безопасный способ соединения:

ГДЕ (ТЗ.Субконто1 = Источник.Субконто1 
    ИЛИ (ТЗ.Субконто1 ЕСТЬ NULL И Источник.Субконто1 ЕСТЬ NULL))

Оптимизация производительности: Индексация

Если ваша Таблица Значений содержит большое количество строк (более нескольких сотен), передача её в запрос без индексации приведет к существенному замедлению работы. Составные типы данных («Субконто») очень тяжелы для поиска. Посмотрим, как правильно проиндексировать колонки при помещении во временную таблицу:


МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;

// Помещаем ТЗ во временную таблицу и сразу создаем индексы
Запрос.Текст = "ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Данные ИЗ &ТЗ КАК ТЗ ИНДЕКСИРОВАТЬ ПО Субконто1, Субконто2";
Запрос.УстановитьПараметр("ТЗ", ТЗ);
Запрос.Выполнить();

Важный нюанс: Индексация по составному полю в 1С работает эффективно, но если количество типов в описании превышает разумные пределы (десятки и сотни), индекс будет занимать много места. Использование типа из метаданных ПВХ (Решение 1) здесь также выигрывает, так как оно ограничивает список типов только необходимыми.

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

← На главную