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

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

1. Базовый метод: Загрузка через Запрос.Выполнить()

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

Пример кода:

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

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

"ВЫБРАТЬ

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

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

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

|ИЗ

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

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

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

Особенности метода:

  • 🔹 Автоматически создаёт колонки в таблице значений на основе полей выборки
  • 🔹 Сохраняет имена колонок и типы данных из запроса
  • 🔹 Подходит для выборок с простой структурой (без вложенных таблиц)
⚠️ Внимание: При использовании этого метода в 1С:Предприятие 8.3.20+ может возникать предупреждение о неявном преобразовании типов, если в выборке есть поля с несовместимыми типами (например, Число и Строка в одной колонке). В таких случаях рекомендуется явно указывать типы при создании таблицы значений.

2. Оптимизированная загрузка: Выборка.Загрузить()

Для выборок с большим количеством строк (от 1000+) эффективнее использовать метод Выборка.Загрузить(). Он позволяет загружать данные порциями, что снижает нагрузку на память и ускоряет обработку.

Пример оптимизированного кода:

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

Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 10000 ..."; // Большая выборка

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

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

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

// Настраиваем колонки заранее для ускорения

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

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

ТаблицаЗначений.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число"));

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

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

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

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

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

КонецЦикла;

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

  • 🚀 Контроль над процессом загрузки (можно добавлять обработку каждой строки)
  • 🔄 Возможность загружать данные пакетами (например, по 1000 строк)
  • 🛠 Гибкость в преобразовании данных "на лету"
📊 Какой объем данных вам чаще приходится обрабатывать в 1С?
До 100 строк
100-1000 строк
1000-10000 строк
Более 10000 строк

3. Загрузка с преобразованием типов данных

Частая проблема при загрузке выборки — несовпадение типов данных между полями выборки и колонками таблицы значений. Например, в базе поле может храниться как Число(10,2), а в таблице значений требуется Строка. В таких случаях нужно явно преобразовывать данные.

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

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

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

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

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

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

Строка = ТаблицаЗначений.Добавить();

Строка.ДатаДокумента = Выборка.ДатаДокумента; // Дата без изменений

// Преобразуем число в строку прописью

Строка.СуммаПрописью = ЧислоПрописью(Выборка.СуммаДокумента, , , , "руб.");

КонецЦикла;

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

Тип в выборке Требуемый тип в ТЗ Метод преобразования
Число Строка Формат(Число, "ЧДЦ=2; ЧРЗ=Нет")
Дата Строка Формат(Дата, "ДФ=dd.MM.yyyy")
Булево Строка ?Истина : "Да" : "Нет"
💡

Если в выборке есть поля с возможными значениями NULL, всегда проверяйте их перед преобразованием: Если ЗначениеЗаполнено(Выборка.Поле) Тогда .... Это предотвратит ошибки выполнения.

4. Загрузка вложенных данных (иерархические выборки)

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

Пример работы с вложенными данными:

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

"ВЫБРАТЬ

| Заказ.Номер КАК Номер,

| Заказ.Дата КАК Дата,

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

| ЗаказСтроки.Количество КАК Количество

|ИЗ

| Документ.ЗаказКлиента КАК Заказ

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

| ПО Заказ.Ссылка = ЗаказСтроки.Ссылка";

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

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

ТаблицаЗаказов.Колонки.Добавить("Дата");

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

ТекущийЗаказ = Неопределено;

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

Если ТекущийЗаказ <> Выборка.Номер Тогда

ТекущийЗаказ = Выборка.Номер;

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

СтрокаЗаказа.Номер = Выборка.Номер;

СтрокаЗаказа.Дата = Выборка.Дата;

СтрокаЗаказа.Товары = Новый ТаблицаЗначений;

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

СтрокаЗаказа.Товары.Колонки.Добавить("Количество");

КонецЕсли;

СтрокаТовара = СтрокаЗаказа.Товары.Добавить();

СтрокаТовара.Номенклатура = Выборка.Номенклатура;

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

КонецЦикла;

Особенности работы с иерархией:

  • 📌 Требует ручного контроля за группировкой данных
  • 📌 Может значительно увеличивать объём используемой памяти
  • 📌 Для больших выборок лучше использовать временные таблицы
Как оптимизировать работу с вложенными выборками?

Для выборок более 5000 строк с вложенными данными рекомендуется:

1. Разбивать запрос на несколько простых выборок

2. Использовать временные таблицы для промежуточных результатов

3. Загружать данные в несколько таблиц значений с последующим объединением

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

При работе с выборками объёмом более 10 000 строк стандартные методы становятся неэффективными. В таких случаях применяют пакетную загрузку с использованием:

  • 📦 Массив для промежуточного хранения
  • 📦 Структура для описания колонок
  • 📦 ПакетныеЗапросы для уменьшения нагрузки на СУБД

Пример пакетной обработки:

// 1. Создаём описание структуры таблицы

СтруктураКолонок = Новый Структура;

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

СтруктураКолонок.Вставить("Количество", Новый ОписаниеТипов("Число"));

// 2. Выполняем запрос с пагинацией

РазмерПакета = 5000;

Смещение = 0;

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

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

ТекстЗапроса = "ВЫБРАТЬ ПЕРВЫЕ " + РазмерПакета + " ...

|ГДЕ ... OFFSET " + Смещение;

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

Если Результат.Количество() = 0 Тогда

Прервать;

КонецЕсли;

// 3. Объединяем результаты

ОбщаяТаблица.Объединить(Результат);

Смещение = Смещение + РазмерПакета;

КонецЦикла;

Критические моменты при пакетной загрузке:

  • 🔴 Всегда ограничивайте размер пакета (оптимально 1000-5000 строк)
  • 🔴 Используйте транзакции для отката при ошибках
  • 🔴 Контролируйте использование памяти через ГлобальныйКонтекст.ПамятьИспользована()

Определить оптимальный размер пакета|Создать структуру колонок заранее|Настроить обработку ошибок|Предусмотреть очистку памяти после загрузки-->

6. Альтернативные подходы: временные таблицы и внешние источники

Для сложных сценариев, когда данные нужно предварительно обработать или они поступают из внешних источников, используют:

Временные таблицы:

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

"ВЫБРАТЬ

| Товары.Наименование,

| СУММА(Движения.Количество) КАК Итого

|ПОМЕСТИТЬ ВТТ_Итоги

|ИЗ ...";

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

// Далее работаем с временной таблицей

Запрос2.Текст = "ВЫБРАТЬ * ИЗ ВТТ_Итоги";

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

Загрузка из внешних источников (XML, JSON, Excel):

// Пример загрузки из JSON

ДанныеJSON = ПолучитьJSONИзВнешнегоИсточника();

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

Для Каждого Элемент Из ДанныеJSON Цикл

Строка = ТаблицаЗначений.Добавить();

Строка.Наименование = Элемент.Наименование;

Строка.Цена = Элемент.Цена;

КонецЦикла;

Когда использовать альтернативные методы:

Сценарий Рекомендуемый метод Преимущества
Сложные многотабличные выборки Временные таблицы Упрощение логики, лучшая читаемость кода
Интеграция с внешними системами Прямая загрузка из JSON/XML Минимизация промежуточных преобразований
Обработка больших файлов (Excel, CSV) Чтение потоками с постраничной загрузкой Экономия памяти, контроль процесса
💡

Временные таблицы особенно эффективны при работе с Microsoft SQL Server, где их обработка оптимизирована на уровне СУБД. В PostgreSQL и IBM DB2 могут быть нюансы с производительностью при больших объёмах данных.

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

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

1. Превышение лимита памяти

⚠️ Внимание: В 1С:Предприятие 8.3 (особенно в веб-клиенте) лимит памяти на одну операцию составляет ~250 МБ. При загрузке выборок более 50 000 строк используйте пакетную обработку или серверные процедуры.

2. Несовпадение типов данных

  • 🔧 Проблема: Ошибка "Тип не соответствует типу колонки"
  • 🔧 Решение: Явно указывайте типы при создании колонок или используйте ЗначениеВСтрокуВнутр() для универсального преобразования

3. Потеря данных при объединении таблиц

  • 🔧 Проблема: При использовании Объединить() дублирующиеся строки замещаются
  • 🔧 Решение: Используйте Добавить() в цикле или ОбъединитьПоКлючам() с явным указанием ключевых полей

4. Зависание при выполнении запроса

  • 🔧 Проблема: Сложный запрос выполняется более 30 секунд
  • 🔧 Решение: Разбивайте запрос на части, используйте индексы, анализируйте план выполнения через Запрос.Выполнить().ПланВременныхТаблиц()

FAQ: Ответы на частые вопросы

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

Да, метод РезультатЗапроса.Выгрузить() автоматически создаёт колонки на основе структуры выборки. Однако для больших таблиц (1000+ строк) рекомендуется явно описывать колонки заранее — это ускоряет процесс на 15-30%.

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

При использовании ITOG BY в запросе результат содержит иерархическую структуру. Для загрузки в таблицу значений нужно:

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

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

Почему при загрузке больших выборок 1С выдаёт ошибку "Недостаточно памяти"?

Эта ошибка возникает при попытке загрузить в память более 200-300 тыс. строк за один раз. Решения:

  • Используйте пакетную загрузку (разбивайте на порции по 5-10 тыс. строк)
  • Переносите логику обработки на сервер (используйте серверные процедуры)
  • Оптимизируйте запрос (добавляйте индексы, убирайте ненужные поля)
  • Для отчётов используйте ПостроительОтчёта вместо таблиц значений

В 1С:Предприятие 8.3.22+ появился механизм потоковой обработки данных (ПотокДанных), который может помочь в таких случаях.

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

В управляемых формах загрузка больших таблиц значений может тормозить интерфейс. Оптимизация:

  • Выполняйте загрузку в фоновом задании (ФоновоеЗадание)
  • Используйте ОтображатьПанельПрогресса() для индикации процесса
  • После загрузки применяйте УстановитьДанныеФормыВКэш()
  • Для динамических списков используйте ОграничениеКоличестваСтрок
Можно ли загрузить в таблицу значений данные из выборки с полями типа "ХранилищеЗначения"?

Поля типа ХранилищеЗначения нельзя напрямую загрузить в таблицу значений стандартными методами. Варианты решений:

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

Пример:

Строка.ДанныеХранилища = ЗначениеВСтрокуВнутр(Выборка.Хранилище);

...

// При необходимости:

ВосстановленноеХранилище = ЗначениеИзСтрокиВнутр(Строка.ДанныеХранилища);