К статье
Практический материал

Разработка и Конфигурация · 13 мин

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

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

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

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

Ниже разобраны все рабочие варианты с примерами кода, особенностями типизации, типичными ошибками и способами проверки результата. Примеры применимы как в обычных, так и в управляемых формах, в тонком и толстом клиенте.

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

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

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

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

"ВЫБРАТЬ

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

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

|ИЗ

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

|ГДЕ

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

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

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

После выполнения переменная ТаблицаТоваров содержит готовую таблицу значений с колонками «Товар» и «Артикул». Имена колонок берутся из псевдонимов полей запроса (то, что указано после КАК), поэтому важно давать полям осмысленные псевдонимы — иначе колонки получат автоматические имена вида «Поле1», что затруднит дальнейшую работу.

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

Обход выборки: когда нужен ручной контроль

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

ТаблицаРезультат = Новый ТаблицаЗначений;

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

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

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

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

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

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

"ВЫБРАТЬ

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

| Остатки.КоличествоОстаток КАК Остаток

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки";

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

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

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

НоваяСтрока.Товар = Выборка.Товар;

НоваяСтрока.Остаток = Выборка.Остаток;

НоваяСтрока.Резерв = ПолучитьРезерв(Выборка.Товар);

НоваяСтрока.Доступно = НоваяСтрока.Остаток - НоваяСтрока.Резерв;

КонецЦикла;

Здесь таблица создаётся заранее с явным описанием колонок, а строки добавляются в цикле. Обращение к полям выборки идёт по псевдонимам из текста запроса — Выборка.Товар, Выборка.Остаток. Если псевдоним не задан, обратиться к полю по имени не получится, и придётся использовать индекс поля в выборке.

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

Обход по группировкам и иерархические таблицы

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

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

"ВЫБРАТЬ

| Продажи.Номенклатура.Родитель КАК Группа,

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

| СУММА(Продажи.Количество) КАК Количество

|ИЗ

| РегистрНакопления.Продажи.Обороты КАК Продажи

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

| Продажи.Номенклатура.Родитель,

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

|ИТОГИ СУММА(Количество) ПО Группа";

ВыборкаГруппы = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

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

СтрокаГруппа = ТаблицаРезультат.Добавить();

СтрокаГруппа.Товар = ВыборкаГруппы.Группа;

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

ВыборкаДетали = ВыборкаГруппы.Выбрать();

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

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

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

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

КонецЦикла;

КонецЦикла;

Если нужна именно иерархическая структура с подчинёнными строками, вместо таблицы значений используйте дерево значений: метод Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией) вернёт объект «ДеревоЗначений», где детальные записи лежат в строках-потомках групп. Это удобно для вывода в элемент формы «Дерево».

Маршрут решения

Как выбрать способ

Нужна просто плоская таблица без обработки строкИспользуйте РезультатЗапроса.Выгрузить() — один вызов без цикла
Каждую строку нужно дополнить вычисляемыми полями или отфильтроватьОбходите выборку через Выбрать() и добавляйте строки вручную
Запрос содержит ИТОГИ и нужна иерархия группа–деталиВыгружайте в дерево значений: Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией)
Таблица нужна с заранее заданными типами колонокСоздайте таблицу вручную с ОписаниеТипов и заполняйте через выборку

Типизация колонок и распространённые нюансы

При использовании Выгрузить() типы колонок определяются запросом, и это иногда приводит к сюрпризам. Например, если в запросе поле вычисляется выражением с ВЫБОР КОГДА ... ИНАЧЕ NULL КОНЕЦ, колонка может получить тип, включающий NULL, и сортировка по ней будет работать не так, как ожидается. Аналогично составные поля (например, «Регистратор») создают колонки составного типа.

При ручном создании таблицы типы задаются явно через Новый ОписаниеТипов. Если не указать тип, колонка будет без ограничения типа — это удобно на этапе прототипирования, но при сортировке смешанных значений (строки и числа в одной колонке) порядок может оказаться неожиданным. Для чисел имеет смысл задавать длину и точность: Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)).

Отдельный случай — когда запрос возвращает поле с типом «ХранилищеЗначения» или строку неограниченной длины. Такие колонки выгружаются корректно, но при выводе в табличное поле формы неограниченные строки могут отображаться не полностью. Если таблица предназначена для формы, ограничьте длину строки в запросе функцией ПОДСТРОКА или задайте квалификаторы при ручном создании колонки.

Типичные ошибки
01
Обращение к полю выборки без псевдонима в запросе — возникает ошибка «Поле не найдено»; всегда указывайте КАК ИмяПоля
02
Использование Выгрузить() и последующее добавление колонок с типом, несовместимым с уже существующими данными
03
Забытая проверка РезультатЗапроса.Пустой() — обход пустой выборки не ошибка, но логика, рассчитанная на наличие строк, отработает некорректно
04
Добавление строк в таблицу внутри цикла обхода той же таблицы — бесконечный цикл или пропуск строк
05
Игнорирование значений NULL из запроса: присвоение NULL в числовую колонку с последующим сложением даёт ошибку преобразования

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

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

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

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

Сообщить("По заданным условиям данные не найдены");

Возврат;

КонецЕсли;

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

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

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

Признак корректного заполнения: количество строк таблицы совпадает с ожидаемым количеством записей выборки, значения ключевых колонок заполнены (не Неопределено и не пустые ссылки), итоговые суммы по числовым колонкам сходятся с итогами запроса. Итог по колонке быстро проверяется методом ТаблицаТоваров.Итог("Количество").

Контрольные точки

Как проверить результат

Количество строк
Норма

ТаблицаЗначений.Количество() равно числу записей выборки

Тревожный признак

Строк меньше ожидаемого — проверьте условия запроса и фильтрацию в цикле

Заполненность ключевых колонок
Норма

Нет пустых ссылок и значений NULL в обязательных полях

Тревожный признак

Встречаются NULL — добавьте ЕСТЬNULL в запросе или обработку в цикле

Итоги по суммам
Норма

ТаблицаЗначений.Итог("Сумма") совпадает с итогом запроса в консоли

Тревожный признак

Итоги расходятся — вероятен пропуск строк или дублирование при нескольких циклах

Типы колонок
Норма

Сортировка и поиск по колонке работают предсказуемо

Тревожный признак

Сортировка чисел идёт как строк — колонка имеет строковый или составной тип

Производительность и большие объёмы данных

Таблица значений размещается в оперативной памяти, поэтому выгружать в неё миллионы строк — плохая идея: сначала вырастет потребление памяти сервером или клиентом, затем возможно аварийное завершение сеанса. Если результат запроса велик, обрабатывайте его выборкой порциями или переносите логику на сторону СУБД — группировками и условиями в тексте запроса.

Для промежуточных расчётов внутри одного запроса или пакета запросов эффективнее использовать временные таблицы (ПОМЕСТИТЬ) вместо выгрузки в таблицу значений и повторной загрузки через МенеджерВременныхТаблиц. Таблицу значений как источник запроса (параметр с ИЗ &ТЗ) стоит применять только для относительно небольших наборов — тысячи, а не сотни тысяч строк.

Если таблица значений заполняется в цикле и по ходу нужен поиск уже добавленных строк, используйте индексы: ТаблицаРезультат.Индексы.Добавить("Товар"). Без индекса каждый вызов Найти() перебирает таблицу целиком, и на больших объёмах время работы растёт квадратично.

Передача таблицы в форму и дальнейшее использование

Частая цель заполнения таблицы значений — показать данные пользователю в форме. В управляемых формах таблица значений как реквизит формы заполняется методом ЗначениеВРеквизитФормы (если реквизит — таблица значений) или напрямую, если реквизит объявлен соответствующего типа. При этом колонки реквизита формы должны совпадать по именам с колонками таблицы, иначе данные не отобразятся.

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

Если данные нужны для отчёта на СКД, таблицу значений передают как внешний набор данных через КомпоновщикМакета и ПроцессорКомпоновки с инициализацией объекта «ВнешниеНаборыДанных». В этом сценарии имена колонок таблицы должны точно совпадать с полями набора данных «Объект» в схеме компоновки.

Итог

Что важно запомнить

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

Частые вопросы

Чем Выгрузить() отличается от Выбрать()?

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

Почему после Выгрузить() колонки называются «Поле1», «Поле2»?

Имена колонок берутся из псевдонимов полей запроса. Если в тексте запроса поля указаны без «КАК ИмяПоля», платформа генерирует автоматические имена. Добавьте осмысленные псевдонимы каждому полю выборки — и колонки получат те же имена.

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

После Выгрузить() добавьте колонку методом Таблица.Колонки.Добавить("Имя", ОписаниеТипов), затем пройдите по строкам циклом «Для каждого Строка Из Таблица Цикл» и заполните значение новой колонки на основе существующих.

Что делать со значениями NULL из запроса?

Лучше устранить NULL на уровне запроса функцией ЕСТЬNULL(Поле, 0) или ЕСТЬNULL(Поле, ""). Если NULL попал в таблицу, проверяйте его через «Значение = NULL» или ЗначениеЗаполнено() перед арифметическими операциями, иначе получите ошибку преобразования типов.

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

Да. Либо объедините выборки одним запросом через ОБЪЕДИНИТЬ ВСЕ и выгрузите один раз, либо выгружайте каждый результат отдельно и переносите строки в итоговую таблицу циклом. Учтите, что у таблицы значений нет метода «слияния» — строки второй таблицы добавляются вручную.

Как выгрузить результат запроса с итогами, сохранив иерархию?

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