Колонка для массива в 1С: что добавлять на самом деле и как

· 9 мин

Содержание

Добавить колонку в массив 1С напрямую нельзя: Массив хранит значения в одну линию, у него есть только индекс элемента. Колонки есть у ТаблицаЗначений, поэтому задача решается одним из трёх способов: перейти на таблицу значений, собрать «массив массивов» или добавить поле в запрос.

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

Почему у массива нет колонок

Массив в 1С одномерный: элементы идут подряд, доступ по номеру, нумерация с нуля. Имён полей и типов колонок у него нет.

Путаницу вносят три похожие вещи:

  • 📋 Таблица значений — строки и именованные колонки. Здесь колонка существует как объект.
  • 🧱 Массив массивов — каждый элемент внешнего массива сам является массивом. Колонкой считается позиция внутри строки.
  • 🗂 Структура и соответствие — пары «ключ — значение». Колонок нет, но ключ играет роль имени поля.

Прежде чем писать код, ответьте себе на вопрос: нужны ли вам имена полей? Если да, массив не подойдёт, и дальше его лучше не мучить.

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

Третий вопрос: куда пойдёт результат. Таблица значений напрямую выводится в табличный документ, связывается с реквизитом формы типа «Таблица значений» и выгружается в табличную часть методом ЗагрузитьКолонку или циклом. Массив массивов для этого придётся разворачивать вручную.

Как добавить колонку в таблицу значений

Это основной сценарий. Колонки таблицы значений хранятся в коллекции Колонки, а добавляет их метод Добавить.

Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Номенклатура");
Таблица.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
Таблица.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)), "Цена, руб.");

Параметры метода по порядку: имя колонки, тип, заголовок, ширина. Обязательно только имя. Тип лучше задавать сразу: колонка без типа принимает что угодно, а значит, ошибки данных всплывут не там, где их допустили.

Добавление колонки в уже заполненную таблицу

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

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

Для Каждого Строка Из Таблица Цикл
	Строка.Сумма = Строка.Количество * Строка.Цена;
КонецЦикла;

Если сумма одинакова для всех строк, цикл не нужен: Таблица.ЗаполнитьЗначения(0, "Сумма") проставит значение в каждую строку за один вызов.

Колонка в нужном месте

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

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

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

После вставки индексы колонок правее сдвигаются на единицу. Если где-то в коде вы обращались к колонке по номеру, Таблица.Колонки[2] теперь указывает на другое поле. Поэтому в коде надёжнее ссылаться на имя, а номер использовать только в цикле по всем колонкам.

Заполнить колонку целиком из массива

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

Значения = Новый Массив;
Значения.Добавить(10);
Значения.Добавить(20);
Значения.Добавить(30);

Таблица.Колонки.Добавить("Остаток");
Таблица.ЗагрузитьКолонку(Значения, "Остаток");

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

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

Как сделать «колонки» в обычном массиве

Если таблица значений избыточна, массив строится как массив массивов. Внешний массив — строки, внутренние — ячейки.

Фиксированная матрица

Для известных размеров есть многомерный массив:

Матрица = Новый Массив(3, 4);   // 3 строки, 4 «колонки»
Матрица[0][0] = 100;
Матрица[2][3] = 250;

Обратите внимание на нумерацию: допустимые индексы строк от 0 до 2, ячеек от 0 до 3. Обращение к Матрица[3][0] вызовет ошибку «Значение индекса выходит за пределы допустимого диапазона».

Динамический массив строк

Когда число строк заранее неизвестно, строки добавляются по ходу:

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

Строка = Новый Массив;
Строка.Добавить("Молоко");
Строка.Добавить(12);
Данные.Добавить(Строка);

Строка = Новый Массив;
Строка.Добавить("Хлеб");
Строка.Добавить(30);
Данные.Добавить(Строка);

Новую «колонку» к такой структуре добавляют циклом: в каждую внутреннюю строку дописывают элемент.

Для Каждого Строка Из Данные Цикл
	Строка.Добавить(Строка[1] * 2);   // третья ячейка: удвоенное количество
КонецЦикла;

У такого подхода есть цена. Вы сами держите в голове, что ячейка 0 — название, ячейка 1 — количество, ячейка 2 — расчёт. Через месяц в коде это уже не прочитать. Если «колонок» больше двух-трёх, переходите на таблицу значений или на массив структур.

Ещё одна ловушка: внутренние массивы в таком «двумерном» массиве разной длины. Платформа этого не запрещает, и строка с двумя ячейками спокойно лежит рядом со строкой с тремя. Обращение к третьей ячейке короткой строки закончится ошибкой выхода за диапазон. Перед чтением проверяйте Строка.Количество() или заполняйте каждую строку по одному шаблону.

Массив структур как компромисс

Структура даёт ячейкам имена, а массив — произвольное число строк. Новая «колонка» — это новый ключ структуры.

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

Элемент = Новый Структура("Наименование, Количество", "Молоко", 12);
Данные.Добавить(Элемент);

Для Каждого Элемент Из Данные Цикл
	Элемент.Вставить("Удвоенное", Элемент.Количество * 2);
КонецЦикла;

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

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

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

Колонка в запросе 1С

Когда данные берутся из регистров и справочников, колонку добавляют не в коде, а в тексте запроса. Тогда нужное поле появится в результате само.

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	Товары.Номенклатура КАК Номенклатура,
|	Товары.Количество КАК Количество,
|	Товары.Цена КАК Цена,
|	Товары.Количество * Товары.Цена КАК Сумма
|ИЗ
|	Документ.РеализацияТоваровУслуг.Товары КАК Товары
|ГДЕ
|	Товары.Ссылка = &Документ";
Запрос.УстановитьПараметр("Документ", ДокументСсылка);

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

Метод Выгрузить превращает результат в таблицу значений, где Сумма уже полноценная колонка. Если после выгрузки нужна ещё одна, добавляйте её через Таблица.Колонки.Добавить, как в первом разделе.

Две оговорки по запросам:

  • ⚠️ Колонка, посчитанная в запросе, получает тип по выражению. Если складываете числа разной точности, проверьте, что тип итога не потерял знаки после запятой.
  • ⚠️ Для вычислений над несколькими таблицами используйте временную таблицу: ПОМЕСТИТЬ ВТ_Данные, а затем второй запрос по ней. Дописывать колонки в готовую выгрузку в цикле на сервере дороже.

Что быстрее и как не потерять производительность

Для больших объёмов (десятки тысяч строк) соотношение примерно такое:

  1. Вычисление в запросе почти всегда быстрее, чем цикл в коде: работает СУБД, а не интерпретатор.
  2. ЗагрузитьКолонку и ЗаполнитьЗначения быстрее построчного цикла: обход выполняет платформа.
  3. Массив массивов расходует память заметнее таблицы значений, потому что каждый внутренний массив — отдельный объект.
  4. Массив структур хуже всех на больших объёмах: на каждую строку создаётся структура с собственными ключами.

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

Отдельно про память. Колонка в таблице на 100 000 строк — это 100 000 дополнительных ячеек, даже если большинство из них пустые. На сервере приложений это неприятно, когда одновременно идёт много сеансов. Если колонка нужна на один шаг расчёта, удалите её сразу после использования через Таблица.Колонки.Удалить, а не держите до конца процедуры.

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

Типичные ошибки при добавлении колонки

Ошибка «Поле объекта не обнаружено» (Поле объекта не обнаружено (Сумма)) — самая частая. Причины:

  • колонку добавили после обращения к ней: порядок строк кода поменялся;
  • имя в Колонки.Добавить отличается от имени в обращении (регистр роли не играет, а вот буква «е» вместо «ё» или латинская «a» вместо кириллической — играет);
  • колонка добавлена в одну таблицу, а читается из другой, например из копии после Скопировать.

Дубль имени. При попытке добавить колонку с существующим именем платформа выдаст ошибку. Перед добавлением проверяйте: Таблица.Колонки.Найти("Сумма") = Неопределено.

Не добавляйте и не удаляйте колонки внутри цикла по строкам той же таблицы. Структура таблицы меняется, а обход продолжается по старому состоянию. Сначала добавьте колонку, потом идите циклом.

Потеря типа. Колонка без ОписаниеТипов принимает всё подряд, и сравнение Строка.Количество > 0 для пустого значения даст неожиданный результат. Задавайте тип с самого начала.

Практический пример: свод продаж с долей

Задача: есть таблица с колонками Номенклатура и Сумма. Нужно добавить колонку Доля в процентах от общего итога.

Итог = Таблица.Итог("Сумма");

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

Если Итог <> 0 Тогда
	Для Каждого Строка Из Таблица Цикл
		Строка.Доля = Окр(Строка.Сумма / Итог * 100, 2);
	КонецЦикла;
КонецЕсли;

Проверка арифметики: при итоге 1 000 и сумме строки 250 доля равна 250 / 1 000 × 100 = 25,00. Сумма долей из-за округления может отличаться от 100 на сотые. Для отчёта это нормально, для проводки нет.

Проверку Итог <> 0 не убирайте: деление на ноль остановит обработку на пустых данных.

Теперь результат при необходимости сортируется: Таблица.Сортировать("Доля Убыв").

Чтобы быстро проверить колонки на готовой таблице, пройдитесь по ним циклом:

Для Каждого Колонка Из Таблица.Колонки Цикл
	Сообщить(Колонка.Имя + ": " + Строка(Колонка.ТипЗначения));
КонецЦикла;
Перед добавлением колонки
Выполнено: 0 / 5

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

Можно ли добавить колонку в обычный массив 1С?
Нет. Массив одномерный, у него нет колонок. Используйте таблицу значений или массив массивов.
Как узнать, есть ли в таблице нужная колонка?
Вызовите Таблица.Колонки.Найти("Имя"). Если колонки нет, метод вернёт Неопределено.
Как удалить колонку из таблицы значений?
Таблица.Колонки.Удалить("Имя") или передайте объект колонки. Данные колонки пропадут вместе с ней.
Чем колонка запроса отличается от колонки таблицы значений?
Колонки результата запроса фиксируются текстом запроса. После Выгрузить получается обычная таблица значений, где колонки можно добавлять и менять.