Как загрузить табличную часть документа или таблицу значений в запрос 1С?

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

Довольно часто в практике разработчика 1С возникает ситуация, когда необходимо обработать данные табличной части документа в запросе ещё до того, как сам документ был записан в базу данных. Типичный пример — процедура ОбработкаЗаполнения, где ссылка на текущий документ ещё отсутствует (объект не записан), но данные в табличной части уже есть и их нужно, например, соединить с данными других документов или регистров. В этой статье мы подробно разберем, как передать табличную часть (ТЧ) или таблицу значений (ТЗ) в запрос, правильно описать колонки и избежать типичных ошибок.

Постановка задачи и выбор стратегии

Рассмотрим ситуацию: мы создаем документ "Возврат товаров от клиента" на основании "Реализации товаров и услуг". Нам нужно в процедуре ОбработкаЗаполнения нового (ещё не записанного) документа дополнить его табличную часть данными из реализации, используя сложную логику запроса. Поскольку ссылки на наш возврат в базе ещё нет, мы не можем просто обратиться к таблице Документ.ВозвратТоваровОтПокупателя.Товары с условием по ссылке. Нам придется передать имеющиеся в оперативной памяти данные объекта в запрос в качестве внешнего источника.

Передача табличной части в параметры запроса

Многие начинающие разработчики ошибочно полагают, что в запрос можно передать только готовую таблицу значений. На самом деле, платформа 1С позволяет передавать табличную часть объекта напрямую. Это работает быстрее и требует меньше кода, так как не нужно тратить ресурсы на выгрузку ТЧ в ТЗ.

Проанализируем пример кода для передачи ТЧ в запрос:


// В модуле объекта документа
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ВременнаяТаблицаТЧ.*
    |ПОМЕСТИТЬ ВТ_ДанныеОбъекта
    |ИЗ
    |	&ВнешнийИсточник КАК ВременнаяТаблицаТЧ";

Запрос.УстановитьПараметр("ВнешнийИсточник", ЭтотОбъект.Товары);

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

Особенности работы с временными таблицами

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

Рассмотрим расширенный пример с соединением:


Запрос = Новый Запрос;
// Используем менеджер временных таблиц для работы с пакетами
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ТчВозврата.Номенклатура КАК Номенклатура,
    |	ТчВозврата.Количество КАК Количество
    |ПОМЕСТИТЬ ВТ_Возврат
    |ИЗ
    |	&ТчВозврата КАК ТчВозврата
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |	ВТ_Возврат.Номенклатура,
    |	ВТ_Возврат.Количество,
    |	РеализацияТовары.НоменклатураПоставщика
    |ИЗ
    |	ВТ_Возврат КАК ВТ_Возврат
    |		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары
    |		ПО ВТ_Возврат.Номенклатура = РеализацияТовары.Номенклатура
    |ГДЕ
    |	РеализацияТовары.Ссылка = &СсылкаНаРеализацию";

Запрос.УстановитьПараметр("ТчВозврата", ЭтотОбъект.Товары);
Запрос.УстановитьПараметр("СсылкаНаРеализацию", ЭтотОбъект.ДокументОснование);

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

Проблема типизации колонок в таблице значений

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

Чтобы избежать ошибок, при создании ТЗ всегда указывайте ОписаниеТипов:


ТЗ = Новый ТаблицаЗначений;
ОписаниеТипаНоменклатура = Новый ОписаниеТипов("СправочникСсылка.Номенклатура");
ОписаниеТипаЧисло = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3));

ТЗ.Колонки.Добавить("Номенклатура", ОписаниеТипаНоменклатура);
ТЗ.Колонки.Добавить("Количество", ОписаниеТипаЧисло);

Если ваша ТЗ получена путем ТЧ.Выгрузить(), типы колонок сохранятся автоматически, и проблем при передаче в запрос не возникнет.

Работа в управляемых формах (ДанныеФормыКоллекция)

Часто программисты пытаются передать в запрос данные прямо из формы: Объект.Товары. Проанализируем ситуацию: на управляемой форме данные табличной части имеют тип ДанныеФормыКоллекция. Этот тип не может быть передан в запрос напрямую.

Посмотрим на варианты решения этой проблемы:

  1. Выгрузка в ТЗ: Выполните Объект.Товары.Выгрузить(). Полученная таблица значений отлично принимается запросом. Это самый простой и рекомендуемый способ.
  2. Преобразование в объект: Используйте функцию РеквизитФормыВЗначение("Объект"). Тогда вы получите полноценный объект документа со всеми его ТЧ, которые можно передать в запрос. Однако помните, что это ресурсоемкая операция, так как система считывает весь объект и компилирует его модуль.

Хитрости конструктора запросов

Главная трудность при написании таких запросов — конструктор не видит полей таблицы, переданной через параметр &ТЗ. Мы не можем просто выбрать нужные поля мышкой, приходится писать текст запроса руками или использовать "заглушки".

Разберем эффективный прием для работы с конструктором:

  1. Временно напишите в тексте запроса вместо &ТЗ имя реальной таблицы базы данных, например, Документ.РеализацияТоваровУслуг.Товары.
  2. Зайдите в конструктор. Теперь все поля ТЧ реализации доступны для выбора. Настройте связи, группировки и поля.
  3. Выйдите из конструктора и вручную замените Документ.РеализацияТоваровУслуг.Товары обратно на ваш параметр &ТЗ.
  4. Не забудьте добавить инструкцию ПОМЕСТИТЬ ВТ_Имя, так как конструктор может её убрать при изменении источников.

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

Если в вашей табличной части много строк (например, более 100-200), соединение временной таблицы с физическими таблицами базы данных может замедлиться. Выясним, как ускорить этот процесс. При помещении данных во временную таблицу обязательно указывайте индексацию по полям, которые участвуют в условиях связи.


ВЫБРАТЬ
    ТЗ.Номенклатура,
    ТЗ.Склад
ПОМЕСТИТЬ ВТ_Данные
ИЗ
    &ТЗ КАК ТЗ
ИНДЕКСИРОВАТЬ ПО
    Номенклатура

Индексирование значительно сократит время поиска записей при выполнении СОЕДИНЕНИЕ, особенно в крупных базах данных под управлением MS SQL или PostgreSQL.

Подводя итог, можно сказать, что механизм передачи таблиц в запрос является мощным инструментом. Главное — помнить об обязательности временных таблиц, следить за типизацией колонок и не забывать про различия между типами данных на клиенте и сервере.

← На главную