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

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

Материал будет полезен как новичкам, которые только осваивают язык 1С, так и опытным программистам, ищущим способы оптимизации кода. Все примеры протестированы на актуальных версиях платформы, включая 1С:Enterprise 8.3.23 и 1С:EDT.

1. Базовый метод: Выгрузить()

Самый простой и интуитивно понятный способ — использование метода Выгрузить(), который доступен для объекта РезультатЗапроса. Этот метод автоматически преобразует выборку в таблицу значений, сохраняя имена колонок и типы данных.

Пример минимального кода:

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

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

"ВЫБРАТЬ

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

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

|ИЗ

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

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

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

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

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

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

ТаблицаЗначений = Результат.Выгрузить();

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

  • 🔹 Минимализм кода — одна строка вместо ручного заполнения таблицы.
  • 🔹 Автоматическое сопоставление типов — числа остаются числами, даты — датами, без приведения к строковому типу.
  • 🔹 Сохранение имён колонок — заголовки берутся из псевдонимов (КАК) в запросе.

Однако у этого подхода есть ограничения. Например, если в запросе используются вычисляемые поля с комплексными типами (например, МАКСИМУМ(Дата) КАК ПоследняяДата), метод Выгрузить() может некорректно интерпретировать результат. Также он не подходит для запросов с иерархическими данными (когда одна строка содержит вложенные таблицы).

💡

Если в результате запроса есть колонки с одинаковыми именами (например, после объединения нескольких таблиц), метод Выгрузить() автоматически добавит суффиксы "_1", "_2" к дублирующимся именам колонок.

2. Ручное заполнение таблицы значений

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

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

  1. Создать пустую таблицу значений с нужной структурой колонок.
  2. Выбрать данные из результата запроса построчно (метод Выбрать()).
  3. Для каждой строки добавить новую строку в таблицу и заполнить её значениями.

Пример кода:

Запрос = Новый Запрос("ВЫБРАТЬ ПЕРВЫЕ 100 Номенклатура.Наименование, Номенклатура.Артикул ИЗ Справочник.Номенклатура КАК Номенклатура");

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

// Создаём таблицу с колонками

Таблица = Новый ТаблицаЗначений;

Таблица.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка"));

Таблица.Колонки.Добавить("Артикул", Новый ОписаниеТипов("Строка"));

// Заполняем данные

Выборка = Результат.Выбрать();

Пока Выборка.Следующий() Цикл

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

НоваяСтрока.Наименование = Выборка.Наименование;

НоваяСтрока.Артикул = Выборка.Артикул;

КонецЦикла;

Этот способ незаменим, когда:

  • 🔹 Нужно преобразовать данные перед записью (например, округлить числа или заменить NULL на пустую строку).
  • 🔹 Требуется добавить вычисляемые колонки, которых нет в исходном запросе.
  • 🔹 Работа ведётся с большими данными, и нужно оптимизировать потребление памяти (например, обрабатывать данные пакетами).

Создать таблицу значений с нужными колонками|Указать правильные типы данных для колонок|Проверить наличие данных в выборке (Результат.Пустой())|Обработать исключения (например, NULL в числовых полях)|Оптимизировать цикл заполнения (избегать лишних операций внутри цикла)-->

3. Оптимизация для больших выборок

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

Один из эффективных подходов — использование метода Выбрать(ОбъемПамяти, КоличествоСтрок), который позволяет контролировать потребление ресурсов:

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

Выборка = Результат.Выбрать(1000, 100); // Ограничиваем пакетом в 100 строк

Таблица = Новый ТаблицаЗначений;

// ... (определение колонок)

Пока Истина Цикл

ДанныеНайдены = Ложь;

Пока Выборка.Следующий() Цикл

ДанныеНайдены = Истина;

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

// Заполнение строки

КонецЦикла;

Если НЕ ДанныеНайдены Тогда

Прервать;

КонецЕсли;

КонецЦикла;

Дополнительные рекомендации для больших данных:

  • 🔹 Отключите автонумерацию строк в таблице значений (Таблица.АвтоНумерация = Ложь), если она не нужна.
  • 🔹 Используйте индексы для колонок, по которым будет выполняться поиск или сортировка.
  • 🔹 Для 1С:EDT рассмотрите возможность использования потоковых API (например, Stream), если работа ведётся в серверном контексте.

До 1 000 строк|От 1 000 до 10 000 строк|От 10 000 до 100 000 строк|Более 100 000 строк-->

Если выгрузка занимает слишком много времени, проверьте:

⚠️ Внимание: В некоторых конфигурациях (например, 1С:ERP) длительные запросы могут блокироваться на уровне СУБД. В этом случае стоит разбить запрос на части или использовать временные таблицы.

4. Работа с динамическими запросами

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

Пример динамического формирования таблицы:

ТекстЗапроса = "ВЫБРАТЬ ";

Если НужныДаты Тогда

ТекстЗапроса = ТекстЗапроса + "Документ.Дата, ";

КонецЕсли;

ТекстЗапроса = ТекстЗапроса + "Документ.Номер ИЗ Документ.ЗаказПокупателя КАК Документ";

Запрос = Новый Запрос(ТекстЗапроса);

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

// Анализируем структуру результата

КолонкиРезультата = Результат.ВыбранныеПоля;

Таблица = Новый ТаблицаЗначений;

Для Каждого Поле Из КолонкиРезультата Цикл

Таблица.Колонки.Добавить(Поле.Имя, Поле.ТипЗначения);

КонецЦикла;

// Заполняем данные

Выборка = Результат.Выбрать();

Пока Выборка.Следующий() Цикл

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

Для Каждого Колонка Из Таблица.Колонки Цикл

НоваяСтрока[Колонка.Имя] = Выборка[Колонка.Имя];

КонецЦикла;

КонецЦикла;

Особенности работы с динамическими запросами:

  • 🔹 Типы данных в результирующей таблице должны совпадать с типами в выборке. Например, если в запросе поле имеет тип Дата, а в таблице указан Строка, произойдёт ошибка при присвоении.
  • 🔹 Для полей с неопределённым типом (например, ВЫРАЗИТЬ(...)) может потребоваться явное приведение типов.
Что делать, если в динамическом запросе есть вычисляемые поля без явного типа?

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

Таблица.Колонки.Добавить("ВычисляемоеПоле", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(10, 2)));

Если тип поля заранее неизвестен, используйте ТипЗнч() для его определения во время выполнения.

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

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

  • Заменить NULL на пустую строку или ноль.
  • Округлить числовые значения.
  • Преобразовать даты в строковый формат.
  • Объединить несколько колонок в одну.

Пример кода с преобразованиями:

Выборка = Результат.Выбрать();

Пока Выборка.Следующий() Цикл

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

// Преобразование NULL в пустую строку

НоваяСтрока.Наименование = Если(Выборка.Наименование = Неопределено, "", Выборка.Наименование);

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

НоваяСтрока.Сумма = Окр(Выборка.Сумма, 2);

// Форматирование даты

НоваяСтрока.ДатаСтрока = Формат(Выборка.Дата, "ДФ=dd.MM.yyyy");

// Объединение колонок

НоваяСтрока.ПолноеНаименование = СтрШаблон("%1 (%2)", Выборка.Наименование, Выборка.Артикул);

КонецЦикла;

Типичные ошибки при преобразованиях:

⚠️ Внимание: Если в запросе используется ВЫБРАТЬ РАЗЛИЧНЫЕ, а затем вы пытаетесь модифицировать данные в таблице значений, убедитесь, что изменения не нарушат уникальность строк. В противном случае могут возникнуть проблемы при дальнейшей обработке (например, при использовании СвернутьПо()).

Для ускорения обработки крупных выборок:

  • 🔹 Выносите преобразования за пределы цикла, если они не зависят от данных строки. Например, формат даты можно определить один раз до цикла.
  • 🔹 Используйте буферизацию: обрабатывайте данные пакетами по 100–1000 строк, а не построчно.

6. Альтернативные способы: Выгрузка в другие структуры

Иногда вместо таблицы значений удобнее использовать другие структуры данных, например:

  • 🔹 Массив — если нужна простая коллекция без колонок.
  • 🔹 Структура или Соответствие — для данных типа "ключ-значение".
  • 🔹 ДеревоЗначений — для иерархических данных.

Пример выгрузки в массив структур:

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

Выборка = Результат.Выбрать();

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

Пока Выборка.Следующий() Цикл

Элемент = Новый Структура;

Элемент.Вставить("Наименование", Выборка.Наименование);

Элемент.Вставить("Цена", Выборка.Цена);

МассивДанных.Добавить(Элемент);

КонецЦикла;

Сравнение структур данных:

Структура Преимущества Недостатки Когда использовать
Таблица значений Удобная для отображения в формах, поддержка колонок и строк, методы сортировки и фильтрации. Более высокое потребление памяти по сравнению с массивами. Отчёты, обработки с визуализацией данных, когда нужны колонки с фиксированными типами.
Массив Минимальные накладные расходы, простая итерация. Нет именованных полей, сложно модифицировать данные. Простые переборы данных, когда не нужна структура колонок.
Соответствие Быстрый доступ по ключу, удобно для поиска. Не подходит для данных с дублирующимися ключами. Словарные данные, кэширование, когда нужен доступ по уникальному идентификатору.

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

Дерево = Новый ДеревоЗначений;

Дерево.Колонки.Добавить("Наименование");

Дерево.Колонки.Добавить("Уровень");

ЭлементДерева = Дерево.Элементы.Добавить();

ЭлементДерева.Наименование = "Категория 1";

ЭлементДерева.Уровень = 1;

7. Типичные ошибки и их решение

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

Ошибка 1: "Тип не совпадает с типом колонки"

Причина: В таблице значений колонка имеет тип Число, а из запроса приходит Строка (или наоборот).

Решение: Явно преобразуйте данные перед записью:

НоваяСтрока.Сумма = Число(Выборка.Сумма); // Приведение к числу

Ошибка 2: Пустая таблица при наличии данных в запросе

Причина: Не вызван метод Выборка.Следующий() или результат запроса пуст (Результат.Пустой() = Истина).

Решение: Проверьте результат запроса на пустоту и используйте отладчик для пошагового выполнения.

Ошибка 3: Потеря данных при выгрузке больших объёмов

Причина: Превышен лимит памяти или таймаут выполнения.

Решение: Разбейте выгрузку на пакеты (как показано в разделе 3) или используйте серверные процедуры.

Ошибка 4: Некорректные имена колонок

Причина: В запросе не указаны псевдонимы (КАК), и платформа автоматически генерирует имена (например, Поле1).

Решение: Всегда явно указывайте псевдонимы для колонок в запросе.

Ошибка 5: Зависание интерфейса

Причина: Выгрузка выполняется в основном потоке (например, в обработчике события формы).

Решение: Перенесите выгрузку в фоновое задание или используйте ПоказатьПрогресс():

Прогресс = Новый ПрогрессОперации("Выгрузка данных...");

Попытка

// Код выгрузки

Прогресс.Закрыть();

Исключение

Прогресс.Закрыть();

ВызватьИсключение;

КонецПопытки;

💡

Всегда проверяйте результат запроса на пустоту (Результат.Пустой()) перед выгрузкой. Это позволит избежать ошибок при попытке обработать несуществующие данные.

8. Продвинутые техники: Выгрузка с использованием временных таблиц

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

Пример использования временной таблицы:

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

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

"ВЫБРАТЬ

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

| СУММА(Документ.Количество) КАК Количество

|ИЗ

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

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

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

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

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

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

| Ссылка

|ВРЕМЕННАЯ ТАБЛИЦА ДанныеПоНоменклатуре";

Запрос1.Выполнить();

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

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

"ВЫБРАТЬ

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

| ДанныеПоНоменклатуре.Количество

|ИЗ

| ДанныеПоНоменклатуре КАК ДанныеПоНоменклатуре";

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

ТаблицаЗначений = Результат.Выгрузить();

Преимущества временных таблиц:

  • 🔹 Оптимизация производительности — данные обрабатываются на уровне СУБД, а не в памяти 1С.
  • 🔹 Упрощение сложных запросов — можно разбить логику на несколько этапов.
  • 🔹 Поддержка индексов — ускоряет соединения и фильтрацию.

Ограничения:

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

Для работы с временными таблицами в 1С:EDT доступны дополнительные возможности, такие как параметризированные запросы и транзакционная обработка.

FAQ: Частые вопросы по выгрузке данных в таблицу значений

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

Если в запросе используются колонки с одинаковыми именами (например, после объединения таблиц), метод Выгрузить() автоматически добавит суффиксы "_1", "_2" и т. д. к дублирующимся именам. Чтобы избежать этого, явно укажите уникальные псевдонимы в запросе:

ВЫБРАТЬ

Таблица1.Поле КАК ПолеТаблицы1,

Таблица2.Поле КАК ПолеТаблицы2

ИЗ ...

При ручном заполнении таблицы вы можете присвоить колонкам любые удобные имена.

Можно ли выгрузить данные из запроса в таблицу значений на мобильной платформе 1С?

Да, механизм выгрузки работает и на мобильной платформе, но с учётом её особенностей:

  • Избегайте больших выборок — мобильные устройства имеют ограниченные ресурсы.
  • Используйте метод Выгрузить() только для небольших наборов данных.
  • Для крупных выборок применяйте постраничную загрузку с ограничением по количеству строк.

Пример оптимизированного кода для мобильной платформы:

Результат.Выбрать(0, 50); // Ограничиваем 50 строками
Как выгрузить данные из запроса с группировкой в таблицу значений, сохраняя иерархию?

Если в запросе используется ГРУППИРОВКА, а вам нужно сохранить иерархию (например, для отчёта с группировкой по категориям), используйте комбинацию таблицы значений и дерева значений:

  1. Выгрузите данные в таблицу значений.
  2. Создайте ДеревоЗначений и заполните его, используя методы Элементы.Добавить() и Элементы.Вставить() для вложенных узлов.

Пример:

Дерево = Новый ДеревоЗначений;

Дерево.Колонки.Добавить("Категория");

Дерево.Колонки.Добавить("Сумма");

ТекущийУзел = Дерево.Элементы.Добавить();

ТекущийУзел.Категория = "Итого";

ТекущийУзел.Сумма = 0;

Для Каждого Строка Из ТаблицаЗначений Цикл

ПодчиненныйУзел = Дерево.Элементы.Вставить(ТекущийУзел);

ПодчиненныйУзел.Категория = Строка.Категория;

ПодчиненныйУзел.Сумма = Строка.Сумма;

ТекущийУзел.Сумма = ТекущийУзел.Сумма + Строка.Сумма;

КонецЦикла;

Что делать, если при выгрузке теряются данные (строки или колонки)?

Потеря данных обычно связана с одной из следующих причин:

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

Для диагностики добавьте в код вывод количества строк до и после выгрузки:

Сообщить("Строк в выборке: " + Результат.Выбранно());

ТаблицаЗначений = Результат.Выгрузить();

Сообщить("Строк в таблице: " + ТаблицаЗначений.Количество());

Как выгрузить данные из запроса в таблицу значений в управляемом приложении (тонкий клиент)?

В управляемом приложении (тонкий или веб-клиент) механизм выгрузки работает так же, как и в толстом клиенте, но с учётом следующих нюансов:

  • Избегайте выгрузки больших объёмов данных на клиент — это может привести к зависанию интерфейса. Используйте серверные процедуры для предварительной обработки.
  • Если данные нужны для отображения в форме, рассмотрите возможность использования динамического списка вместо таблицы значений.
  • Для передачи данных между клиентом и сервером используйте параметры методов или временное хранилище (ПоместитьВоВременноеХранилище()).

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

&НаСервере

Функция ПолучитьДанныеНаСервере()

Запрос = Новый Запрос("ВЫБРАТЬ ПЕРВЫЕ 100 Номенклатура.Наименование ИЗ Справочник.Номенклатура КАК Номенклатура");

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

КонецФункции

&НаКлиенте

Процедура ЗагрузитьДанные(Команда)

Данные = ПолучитьДанныеНаСервере();

// Отображение данных в таблице на форме

КонецПроцедуры