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

В этой статье мы разберём 5 проверенных способов вывода результата запроса в табличную часть — от простейшего цикла Для Каждого до оптимизированных методов с использованием ЗагрузкаДанных и МассивСтруктур. Особое внимание уделим типичным ошибкам, которые допускают даже опытные программисты, и покажем, как их избежать. Если вы работаете с 1С 8.3 (включая последние релизы) или поддерживаете устаревшие конфигурации на 8.2, здесь найдёте актуальные решения.

Материал будет полезен как начинающим разработчикам, так и тем, кто хочет оптимизировать свой код. Все примеры протестированы на платформе 1С:Предприятие 8.3.23, но приведенные методы работают и в более ранних версиях (с учётом синтаксических особенностей).

1. Базовый метод: цикл Для Каждого по результату запроса

Самый простой и интуитивно понятный способ — это перебор строк результата запроса в цикле и добавление их в табличную часть. Этот метод подходит для небольших наборов данных (до 1000 строк) и часто используется в типовых конфигурациях.

Пример кода:

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Номенклатура.Ссылка КАК Номенклатура,

| Номенклатура.Артикул,

| 10 КАК Количество

|ИЗ

| Справочник.Номенклатура КАК Номенклатура

|ГДЕ

| Номенклатура.ЭтоГруппа = ЛОЖЬ";

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

ТабличнаяЧасть.Очистить();

Пока РезультатЗапроса.Следующий() Цикл

НоваяСтрока = ТабличнаяЧасть.Добавить();

НоваяСтрока.Номенклатура = РезультатЗапроса.Номенклатура;

НоваяСтрока.Артикул = РезультатЗапроса.Артикул;

НоваяСтрока.Количество = РезультатЗапроса.Количество;

КонецЦикла;

Плюсы метода:

  • 🔹 Простота реализации — понятно даже новичку
  • 🔹 Гибкость: можно обрабатывать каждую строку индивидуально
  • 🔹 Не требует дополнительных объектов (например, Массив или Структура)

Минусы метода:

  • 🐢 Медленная работа при большом количестве строк (от 5000+)
  • 🔄 Каждая итерация цикла вызывает событие ПриИзменении в табличной части
  • 📊 Нет контроля за целостностью данных при прерывании
⚠️ Внимание: Если табличная часть содержит реквизиты с проверкой заполнения (ОбщийРеквизит.Обязательное), то при добавлении строк в цикле может возникать исключение. В этом случае либо отключите проверку на время заполнения, либо используйте метод ЗаполнитьЗначенияСвойств().
💡

Для ускорения работы отключите обновление экрана перед циклом с помощью ПриостановитьОбновлениеИнтерфейса() и включите его обратно после завершения заполнения.

2. Оптимизированный способ: использование МассивСтруктур и ЗагрузкаДанных

Для работы с большими объёмами данных (от 5000 строк) рекомендуется использовать МассивСтруктур в связке с методом ЗагрузитьДанные(). Этот подход значительно ускоряет процесс, так как:

  • 🚀 Данные загружаются пакетом, а не построчно
  • 🔒 Минимизируется количество вызовов событий табличной части
  • 🛠️ Легче контролировать ошибки загрузки

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

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Контрагент.Ссылка КАК Контрагент,

| Договор.Номер КАК НомерДоговора,

| СУММА(Документ.СуммаДокумента) КАК Сумма

|ИЗ

| Документ.РеализацияТоваровУслуг КАК Документ

| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Контрагент

| ПО Документ.Контрагент = Контрагент.Ссылка

| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ДоговорыКонтрагентов КАК Договор

| ПО Документ.Договор = Договор.Ссылка

|СГРУППИРОВАТЬ ПО

| Контрагент,

| Договор.Номер";

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

МассивДанных = Новый Массив;

Пока РезультатЗапроса.Следующий() Цикл

СтруктураСтроки = Новый Структура;

СтруктураСтроки.Вставить("Контрагент", РезультатЗапроса.Контрагент);

СтруктураСтроки.Вставить("НомерДоговора", РезультатЗапроса.НомерДоговора);

СтруктураСтроки.Вставить("Сумма", РезультатЗапроса.Сумма);

МассивДанных.Добавить(СтруктураСтроки);

КонецЦикла;

ТабличнаяЧасть.Очистить();

ТабличнаяЧасть.ЗагрузитьДанные(МассивДанных);

Критическое замечание: метод ЗагрузитьДанные() игнорирует обработчики событий ПередЗаписью и ПриЗаписи в табличной части. Если ваша логика зависит от этих событий, используйте альтернативный подход с временным отключением обработчиков.

Создать массив структур для хранения данных|Отключить обновление интерфейса (ПриостановитьОбновлениеИнтерфейса())|Очистить табличную часть перед загрузкой|Проверить соответствие имён полей в структуре и табличной части|Восстановить интерфейс после загрузки (ВозобновитьОбновлениеИнтерфейса())

-->

3. Работа с временными таблицами и Объект.Заполнить

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

Алгоритм действий:

  1. Создать временную таблицу в запросе
  2. Заполнить её данными
  3. Перенести данные в табличную часть объекта

Пример с использованием Заполнить():

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Товар.Ссылка КАК Товар,

| Товар.Артикул,

| Товар.ЕдиницаИзмерения КАК Единица,

| 5 КАК Количество

|ПОМЕСТИТЬ ВТ_Товары

|ИЗ

| Справочник.Номенклатура КАК Товар

|ГДЕ

| Товар.ЭтоГруппа = ЛОЖЬ

|

|////////////////////////////////////////////////

|ВЫБРАТЬ

| ВТ_Товары.Товар КАК Товар,

| ВТ_Товары.Артикул,

| ВТ_Товары.Единица,

| ВТ_Товары.Количество * 2 КАК ИтоговоеКоличество

|ИЗ

| ВТ_Товары КАК ВТ_Товары";

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

ТабличнаяЧасть.Очистить();

ТабличнаяЧасть.Заполнить(РезультатЗапроса);

⚠️ Важный нюанс: Метод Заполнить() автоматически сопоставляет имена колонок результата запроса с именами реквизитов табличной части. Если имена не совпадают, данные не будут загружены. Чтобы избежать ошибок, используйте псевдонимы (КАК) в запросе, соответствующие именам реквизитов.

Цикл Для Каждого|МассивСтруктур + ЗагрузкаДанных|Временные таблицы + Заполнить|Другое-->

4. Вывод данных с преобразованием типов

Часто данные из запроса требуют преобразования перед выводом в табличную часть. Например:

  • 🔢 Числовые значения нужно округлить
  • 📅 Даты привести к определённому формату
  • 🔤 Строки обрезать или дополнить
  • 🔍 Ссылки на справочники проверить на существование

Рассмотрим пример с преобразованием типов и проверкой ссылок:

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Документ.Дату КАК ДатаДокумента,

| Документ.СуммаДокумента КАК Сумма,

| Документ.Контрагент КАК Контрагент,

| Документ.Комментарий КАК Примечание

|ИЗ

| Документ.ПоступлениеТоваровУслуг КАК Документ";

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

ТабличнаяЧасть.Очистить();

Пока РезультатЗапроса.Следующий() Цикл

НоваяСтрока = ТабличнаяЧасть.Добавить();

// Преобразование даты в строку с нужным форматом

НоваяСтрока.Дата = Формат(РезультатЗапроса.ДатаДокумента, "ДФ=dd.MM.yyyy");

// Округление суммы до 2 знаков

НоваяСтрока.Сумма = Окр(РезультатЗапроса.Сумма, 2);

// Проверка существования контрагента

Если НЕ РезультатЗапроса.Контрагент.Пустая() Тогда

НоваяСтрока.Контрагент = РезультатЗапроса.Контрагент;

Иначе

НоваяСтрока.Контрагент = Справочники.Контрагенты.НайтиПоНаименованию("Неопределённый");

КонецЕсли;

// Обрезка комментария до 100 символов

НоваяСтрока.Примечание = Лев(РезультатЗапроса.Примечание, 100);

КонецЦикла;

⚠️ Внимание: При преобразовании ссылочных типов (например, СправочникСсылка.Контрагенты) всегда проверяйте их на пустоту с помощью метода Пустая(). Попытка присвоить пустую ссылку реквизиту табличной части вызовет ошибку.
Что делать, если в запросе возвращаются NULL-значения?

В 1С NULL-значения из запроса преобразуются в Неопределён. Чтобы избежать ошибок, используйте конструкцию ВЫРАЗИТЬ(Поле КАК Строка) для приведения к строковому типу или проверяйте на ТипЗнч(Значение) = Тип("Неопределено").

5. Обработка больших данных: постраничная загрузка

При работе с очень большими выборками (10 000+ строк) рекомендуется использовать постраничную загрузку. Это позволяет:

  • 📥 Избежать перегрузки памяти
  • 🔄 Контролировать процесс загрузки
  • ⏱️ Оптимизировать время выполнения

Реализация постраничной загрузки:

РазмерСтраницы = 1000; // Количество строк за одну итерацию

НомерСтраницы = 0;

ОбщееКоличество = 0;

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ &РазмерСтраницы СТРОКИ

| Номенклатура.Ссылка КАК Номенклатура,

| Номенклатура.Наименование,

| Номенклатура.Артикул

|ИЗ

| Справочник.Номенклатура КАК Номенклатура

|ГДЕ

| НЕ Номенклатура.ПометкаУдаления

|УПОРЯДОЧИТЬ ПО

| Номенклатура.Код

|

|ИНДЕКСИРОВАТЬ ПО

| НомерСтраницы

|ВЫБРАТЬ КОЛИЧЕСТВО(RAZR) КАК ОбщееКоличество";

// Получаем общее количество строк

Запрос.УстановитьПараметр("РазмерСтраницы", 1);

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

ВыборкаОбщееКоличество = Результат.Выбрать();

Если ВыборкаОбщееКоличество.Следующий() Тогда

ОбщееКоличество = ВыборкаОбщееКоличество.ОбщееКоличество;

КонецЕсли;

// Постраничная загрузка

Пока НомерСтраницы * РазмерСтраницы < ОбщееКоличество Цикл

Запрос.УстановитьПараметр("РазмерСтраницы", РазмерСтраницы);

Запрос.УстановитьПараметр("НомерСтраницы", НомерСтраницы);

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

Пока РезультатЗапроса.Следующий() Цикл

НоваяСтрока = ТабличнаяЧасть.Добавить();

НоваяСтрока.Номенклатура = РезультатЗапроса.Номенклатура;

НоваяСтрока.Наименование = РезультатЗапроса.Наименование;

НоваяСтрока.Артикул = РезультатЗапроса.Артикул;

КонецЦикла;

НомерСтраницы = НомерСтраницы + 1;

Сообщить(Формат("Загружено %1 из %2 строк", НомерСтраницы * РазмерСтраницы, ОбщееКоличество));

КонецЦикла;

📌 Совет: Для ускорения постраничной загрузки используйте индексирование по ключевому полю (в примере — УПОРЯДОЧИТЬ ПО Номенклатура.Код). Это позволит базе данных быстрее находить нужные строки.

Типичные ошибки и как их избежать

Даже опытные разработчики иногда допускают ошибки при выводе данных в табличные части. Вот самые распространённые из них:

Ошибка Причина Решение
Данные не выводятся в табличную часть Не совпадают имена колонок в запросе и реквизитов табличной части Используйте псевдонимы КАК в запросе или переименуйте реквизиты
Ошибка "Тип не совпадает" Попытка присвоить значение неверного типа (например, строку в числовой реквизит) Преобразуйте данные с помощью Число(), Строка() и т.д.
Медленная работа при большом объёме данных Построчная обработка в цикле Для Каждого Используйте МассивСтруктур + ЗагрузитьДанные()
Потеря данных при прерывании Отсутствует контроль транзакций Оберните загрузку в НачатьТранзакцию()/ЗафиксироватьТранзакцию()
Не работают события табличной части Метод ЗагрузитьДанные() игнорирует обработчики Временно отключите события или используйте цикл
⚠️ Внимание: Если вы работаете с управляемыми формами, помните, что табличные части на форме и в объекте базы данных — это разные объекты. Для вывода данных на форму сначала загрузите их в табличную часть документа/справочника, а затем обновите форму методом Обновить().
💡

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

FAQ: Частые вопросы по выводу запроса в табличную часть

Можно ли вывести результат запроса в табличную часть без цикла?

Да, для этого используйте метод Заполнить() (если имена колонок совпадают) или ЗагрузитьДанные() с предварительным формированием массива структур. Однако эти методы имеют ограничения:

  • 🔹 Заполнить() требует точного совпадения имён колонок
  • 🔹 ЗагрузитьДанные() игнорирует обработчики событий табличной части

Для полного контроля над процессом лучше использовать цикл.

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

При работе с группировкой в запросе:

  1. Используйте агрегатные функции (СУММА, КОЛИЧЕСТВО и т.д.)
  2. Убедитесь, что в табличной части есть реквизиты для хранения итоговых значений
  3. При необходимости добавьте в запрос поле для идентификации группы (например, Контрагент.Наименование КАК Группа)

Пример:

Запрос.Текст =

"ВЫБРАТЬ

| Контрагент.Наименование КАК Контрагент,

| СУММА(Документ.СуммаДокумента) КАК ИтоговаяСумма,

| КОЛИЧЕСТВО(RAZR) КАК КоличествоДокументов

|ИЗ

| Документ.РеализацияТоваровУслуг КАК Документ

|СГРУППИРОВАТЬ ПО

| Контрагент.Наименование";

Почему при выводе данных в табличную часть возникает ошибка "Объект не найден"?

Эта ошибка typична в трёх случаях:

  1. В запросе возвращается пустая ссылка на справочник/документ, но реквизит табличной части не поддерживает пустые значения. Решение: добавьте проверку ЕСЛИ НЕ Значение.Пустая().
  2. Имя реквизита в табличной части не совпадает с именем колонки в запросе. Решение: используйте псевдонимы КАК.
  3. Табличная часть не инициализирована (например, в новом документе). Решение: проверьте, что объект сохранён (ЭтотОбъект.Ссылка.Пустая() = ЛОЖЬ).
Как ускорить вывод 50 000 строк в табличную часть?

Для работы с большими объёмами данных:

  1. Используйте постраничную загрузку (см. раздел 5)
  2. Отключите обновление интерфейса: ПриостановитьОбновлениеИнтерфейса()
  3. Загружайте данные пакетом через МассивСтруктур + ЗагрузитьДанные()
  4. Если возможно, перенесите логику обработки на сторону СУБД (в сам запрос)

⚠️ Важно: При загрузке более 100 000 строк рассмотрите возможность использования внешних обработок или фоновых заданий, чтобы не блокировать интерфейс пользователя.

Можно ли вывести в табличную часть данные из запроса с параметрами?

Да, для этого:

  1. Объявите параметры в тексте запроса: ГДЕ Документ.Дата МЕЖДУ &НачалоПериода И &КонецПериода
  2. Установите значения параметров перед выполнением: Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ТекущаяДата()))
  3. Выполните запрос и обработайте результат стандартными методами

Пример:

Запрос.Текст =

"ВЫБРАТЬ

| Документ.Номер КАК Номер,

| Документ.Дату КАК Дата

|ИЗ

| Документ.ПоступлениеТоваровУслуг КАК Документ

|ГДЕ

| Документ.Дата МЕЖДУ &НачалоПериода И &КонецПериода";

Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДата()));

Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(ТекущаяДата()));