Как выполнить запрос к табличной части нового незаписанного документа

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

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

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

Механизм работы запроса с данными в оперативной памяти

Прежде всего, выясним причину проблемы. Объект запроса Новый Запрос исполняется на стороне сервера баз данных (например, MS SQL или PostgreSQL). Чтобы СУБД смогла «увидеть» данные вашей табличной части, они должны быть туда переданы. Поскольку записи в основной таблице ТЧ еще нет, нам остается только один путь: передать содержимое табличной части в запрос как внешний параметр в виде Таблицы Значений.

Рассмотрим базовый алгоритм действий:

  1. Выгружаем табличную часть документа в объект типа ТаблицаЗначений.
  2. Устанавливаем эту таблицу как параметр запроса.
  3. В тексте запроса описываем структуру этой таблицы и помещаем ее во Временную Таблицу.
  4. Производим необходимые манипуляции (соединения, группировки) с этой временной таблицей.

Решение 1: Выгрузка ТЧ и использование временных таблиц

Самый надежный способ — это явная выгрузка данных. Посмотрим на пример кода, который позволяет работать с данными ТЧ Товары незаписанного документа:


// 1. Выгружаем табличную часть в Таблицу Значений
ТЗ_Товары = ЭтотОбъект.Товары.Выгрузить();

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

// 3. Устанавливаем выгруженную таблицу как параметр
Запрос.УстановитьПараметр("ТЧ", ТЗ_Товары);

// 4. Выполняем запрос
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    // Обработка результата
КонецЦикла;

В данном примере мы использовали конструкцию ПОМЕСТИТЬ. Это критически важно, так как 1С не позволяет выполнять сложные операции (например, соединения ЛЕВОЕ СОЕДИНЕНИЕ) напрямую с параметром типа ТаблицаЗначений. Сначала данные должны «переехать» во временную таблицу в памяти СУБД.

Решение 2: Особенности для управляемых форм (8.3)

Проанализируем ситуацию в контексте управляемого приложения. На клиенте данные табличной части представлены типом ДанныеФормыКоллекция. Этот тип нельзя напрямую передать в запрос на сервер. Если вы находитесь в модуле формы, процедуру обработки данных ТЧ следует реализовать &НаСервере.

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

  1. Передаем данные с клиента на сервер.
  2. Преобразуем данные формы в объект или напрямую работаем с реквизитом Объект.
  3. Используем метод Выгрузить() для получения ТаблицыЗначений.

&НаСервере
Процедура ПроверитьДанныеТЧНаСервере()
    
    // Получаем таблицу значений из данных формы
    // Если мы работаем с реквизитом "Объект", то:
    ТаблицаДляЗапроса = Объект.Товары.Выгрузить();
    
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ * ПОМЕСТИТЬ ВТ ИЗ &ТЗ КАК ТЗ; ВЫБРАТЬ * ИЗ ВТ";
    Запрос.УстановитьПараметр("ТЗ", ТаблицаДляЗапроса);
    
    // Далее стандартная обработка...
    
КонецПроцедуры

Важные технические нюансы и рекомендации

Рассмотрим более глубокие аспекты, которые помогут избежать ошибок при работе с большими объемами данных или сложной логикой.

1. Типизация колонок Таблицы Значений

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

2. Проблема дублей в незаписанной ТЧ

Выясним важную деталь: в незаписанном документе пользователь мог ввести одну и ту же номенклатуру в разные строки. При записи в базу данных часто срабатывают механизмы контроля или свертки, но в оперативной памяти данные «сырые». Если ваша задача — проверить остатки по ТЧ, обязательно используйте группировку (СГРУППИРОВАТЬ ПО) во временной таблице, иначе соединение с таблицей остатков выдаст некорректные (завышенные) данные из-за дублирования строк.

3. Индексация временных таблиц

Если в табличной части много строк (сотни или тысячи) и вы планируете соединять ее с физическими таблицами базы данных (например, с регистром накопления ТоварыНаСкладах.Остатки), проанализируем производительность. В тексте запроса после помещения данных во временную таблицу стоит добавить инструкцию индексации:

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

4. Прямая передача ТЧ в параметр

В некоторых случаях (в зависимости от версии платформы) 1С позволяет передать табличную часть напрямую: Запрос.УстановитьПараметр("ТЧ", Товары), не вызывая явный метод Выгрузить(). Однако, практика показывает, что метод с Выгрузить() в ТаблицуЗначений является более универсальным и предсказуемым, так как он гарантирует передачу данных в виде независимого набора записей.

Когда запрос к незаписанному документу — плохая идея?

Проанализируем ситуацию, описанную в одном из сообщений форума: «Зачем отправлять ТЧ на сервер, чтобы потом тащить ее назад?». Это справедливое замечание. Если вам нужно просто посчитать итог по колонке или найти строку, лучше использовать методы коллекции: Объект.Товары.Итог("Сумма") или Объект.Товары.НайтиСтроки(). Запрос оправдан только тогда, когда данные ТЧ нужно соединить с данными других таблиц БД (остатками, ценами, спецификациями) или выполнить сложную группировку, которую тяжело реализовать перебором.

Итоги

Для успешного выполнения запроса к ТЧ нового документа мы должны:

Используя этот подход, мы получаем мощный инструмент для предварительного анализа данных документа еще до момента его окончательного сохранения в системе.

← На главную