Таблица значений 1С — главная коллекция для работы с данными в памяти: строки и колонки, как у табличной части документа, только без записи в базу. В неё выгружают результат запроса, через неё собирают данные для печатной формы, отчёта или загрузки из Excel, в ней считают промежуточные итоги при проведении. Ниже — как в 1С 8.3 программно создать таблицу с типизированными колонками, найти и удалить строки, свернуть данные, передать таблицу в запрос и на форму. В конце — шпаргалка по методам и приёмы, из-за которых код тормозит.
Тип ТаблицаЗначений существует на сервере, в толстом клиенте и во внешнем соединении. В тонком клиенте и веб-клиенте его нет. Поэтому в управляемой форме строка Новый ТаблицаЗначений внутри процедуры с директивой &НаКлиенте заканчивается ошибкой «Тип не определен (ТаблицаЗначений)». Вернуть таблицу из серверной функции в клиентскую процедуру тоже не выйдет: этот тип не передаётся между клиентом и сервером.
Реквизит формы с типом ТаблицаЗначений — другое дело. На клиенте он виден как ДанныеФормыКоллекция: у неё есть Добавить(), Удалить(), Количество(), НайтиСтроки(), Итог(), Очистить(), но нет Свернуть(), ВыгрузитьКолонку() и Скопировать(). Правило простое: вся обработка — на сервере, на клиент уходит готовый результат.
Программно таблицы значений в 1С получают двумя путями: создают конструктором или выгружают готовые данные. Конструктор Новый ТаблицаЗначений даёт таблицу без колонок. Колонки добавляют методом Колонки.Добавить(Имя, ТипЗначения, Заголовок, Ширина), обязательно только имя. Тип задают объектом ОписаниеТипов с квалификаторами.
Готовые данные выгружают так:
Запрос.Выполнить().Выгрузить() — колонки и их типы берутся из запроса;ДокументОбъект.Товары.Выгрузить() — копия табличной части, обратно её кладут методом Загрузить();РеквизитФормыВЗначение("ИмяРеквизита") — таблица из реквизита формы, только на сервере;Таблица.СкопироватьКолонки() — пустая таблица с той же структурой.Рабочий пример — общий модуль для таблицы продаж и форма обработки со сводкой по складам. Типы колонок примитивные, код компилируется в любой конфигурации с режимом совместимости от 8.3.6.
// ===== Общий модуль ТаблицыЗначенийСервер =====
// Свойства модуля: флажок «Сервер». «Вызов сервера» не нужен:
// модуль вызывается из серверных процедур формы. Платформа 8.3.6 и новее,
// режим совместимости конфигурации не ниже 8.3.6 (СтрСоединить, СтрШаблон).
#Область ПрограммныйИнтерфейс
// Создаёт пустую таблицу продаж с типизированными колонками.
//
// Возвращаемое значение:
// ТаблицаЗначений - колонки Склад, Артикул, Дата, Количество, Сумма.
//
Функция НоваяТаблицаПродаж() Экспорт
ТипСтрока = Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(50));
ТипДата = Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.Дата));
ТипКоличество = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3));
ТипСумма = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2));
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Склад", ТипСтрока, "Склад");
Таблица.Колонки.Добавить("Артикул", ТипСтрока, "Артикул");
Таблица.Колонки.Добавить("Дата", ТипДата, "Дата продажи");
Таблица.Колонки.Добавить("Количество", ТипКоличество, "Количество");
Таблица.Колонки.Добавить("Сумма", ТипСумма, "Сумма");
Возврат Таблица;
КонецФункции
// Добавляет в таблицу строку продажи.
//
// Возвращаемое значение:
// СтрокаТаблицыЗначений - добавленная строка.
//
Функция ДобавитьПродажу(Таблица, Склад, Артикул, Дата, Количество, Сумма) Экспорт
НоваяСтрока = Таблица.Добавить();
НоваяСтрока.Склад = Склад;
НоваяСтрока.Артикул = Артикул;
НоваяСтрока.Дата = Дата;
НоваяСтрока.Количество = Количество;
НоваяСтрока.Сумма = Сумма;
Возврат НоваяСтрока;
КонецФункции
// Удаляет строки, в которых и количество, и сумма равны нулю.
// Обход идёт с конца: удаление не сдвигает строки, которые ещё не проверены.
//
Процедура УдалитьНулевыеСтроки(Таблица) Экспорт
ВсегоСтрок = Таблица.Количество();
Для Шаг = 1 По ВсегоСтрок Цикл
СтрокаТаблицы = Таблица[ВсегоСтрок - Шаг];
Если СтрокаТаблицы.Количество = 0 И СтрокаТаблицы.Сумма = 0 Тогда
Таблица.Удалить(СтрокаТаблицы);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
// Возвращает итоги по складам и артикулам, отсортированные по складу
// и по убыванию суммы. Исходная таблица не меняется.
//
// Параметры:
// Продажи - ТаблицаЗначений - таблица из НоваяТаблицаПродаж().
// Склад - Строка - если заполнен, в итоги попадёт только этот склад.
//
// Возвращаемое значение:
// ТаблицаЗначений - колонки Склад, Артикул, Количество, Сумма.
//
Функция СводкаПоСкладам(Продажи, Склад = "") Экспорт
Колонки = "Склад, Артикул, Количество, Сумма";
Если ПустаяСтрока(Склад) Тогда
Сводка = Продажи.Скопировать(, Колонки);
Иначе
СтрокиСклада = Продажи.НайтиСтроки(Новый Структура("Склад", Склад));
Сводка = Продажи.Скопировать(СтрокиСклада, Колонки);
КонецЕсли;
Сводка.Свернуть("Склад, Артикул", "Количество, Сумма");
Сводка.Сортировать("Склад, Сумма Убыв");
Возврат Сводка;
КонецФункции
// Преобразует таблицу значений в массив структур с теми же именами колонок.
// Массив структур, в отличие от таблицы, можно вернуть на клиент.
//
Функция ТаблицаВМассивСтруктур(Таблица) Экспорт
ИменаКолонок = Новый Массив;
Для Каждого Колонка Из Таблица.Колонки Цикл
ИменаКолонок.Добавить(Колонка.Имя);
КонецЦикла;
КлючиСтруктуры = СтрСоединить(ИменаКолонок, ",");
Результат = Новый Массив;
Для Каждого СтрокаТаблицы Из Таблица Цикл
Элемент = Новый Структура(КлючиСтруктуры);
ЗаполнитьЗначенияСвойств(Элемент, СтрокаТаблицы);
Результат.Добавить(Элемент);
КонецЦикла;
Возврат Результат;
КонецФункции
#КонецОбласти
// ===== Модуль формы обработки (управляемая форма) =====
// Реквизиты формы: Склад (Строка) и Сводка (ТаблицаЗначений) с колонками
// Склад, Артикул, Количество, Сумма, добавленными в конфигураторе.
&НаКлиенте
Процедура Сформировать(Команда)
СформироватьНаСервере();
// На клиенте Сводка - это ДанныеФормыКоллекция: Количество() и Итог() есть, Свернуть() и Скопировать() нет.
ПоказатьПредупреждение(, СтрШаблон("Строк в сводке: %1", Сводка.Количество()));
КонецПроцедуры
&НаСервере
Процедура СформироватьНаСервере()
Продажи = ТаблицыЗначенийСервер.НоваяТаблицаПродаж();
// Пример данных. В рабочей обработке таблицу вернёт запрос: Запрос.Выполнить().Выгрузить().
ТаблицыЗначенийСервер.ДобавитьПродажу(Продажи, "Основной", "A-100", '20250303', 5, 1500);
ТаблицыЗначенийСервер.ДобавитьПродажу(Продажи, "Основной", "A-100", '20250304', 2, 600);
ТаблицыЗначенийСервер.ДобавитьПродажу(Продажи, "Основной", "B-200", '20250304', 0, 0);
ТаблицыЗначенийСервер.ДобавитьПродажу(Продажи, "Филиал", "A-100", '20250305', 1, 310);
ТаблицыЗначенийСервер.УдалитьНулевыеСтроки(Продажи);
Результат = ТаблицыЗначенийСервер.СводкаПоСкладам(Продажи, Склад);
ЗначениеВРеквизитФормы(Результат, "Сводка");
КонецПроцедуры
ОписаниеТипов у каждой колонки. В новой строке типизированная колонка сразу содержит пустое значение своего типа: 0, пустую строку, пустую дату. У колонки без типа там Неопределено, и выражение СтрокаТаблицы.Сумма + 100 падает с ошибкой. Второй довод — запрос: без типов таблицу не передать параметром.
Добавить() и обращение к колонкам. Метод возвращает СтрокаТаблицыЗначений; к ячейке обращаются через точку (НоваяСтрока.Сумма) или в квадратных скобках (СтрокаТаблицы["Сумма"]), если имя колонки лежит в переменной. Если поля совпадают по именам, строку заполняют одной командой ЗаполнитьЗначенияСвойств(НоваяСтрока, Источник). Подробнее — в статье о строке таблицы значений.
Обратный цикл в УдалитьНулевыеСтроки. Удаление строки сдвигает все следующие на одну позицию. Если удалять в цикле Для Каждого или по индексу от начала, строка сразу за удалённой будет пропущена. При обходе с конца сдвигаются только уже проверенные строки.
Скопировать перед Свернуть. Свернуть("Склад, Артикул", "Количество, Сумма") меняет саму таблицу: группирует по первому списку колонок, суммирует второй, а все прочие колонки удаляет. Чтобы не испортить исходные данные, сворачивают копию. НайтиСтроки возвращает массив строк, и Скопировать принимает его первым параметром. Есть и вариант со структурой отбора, но массив работает в любой версии 8.3.
Сортировать("Склад, Сумма Убыв"). Направление пишут через пробел после имени колонки: Возр (по умолчанию) или Убыв.
ТаблицаВМассивСтруктур. Массив структур свободно передаётся на клиент. ЗаполнитьЗначенияСвойств копирует в структуру ячейки с совпадающими именами. СтрСоединить и СтрШаблон есть в платформе начиная с 8.3.6 и доступны, если режим совместимости конфигурации не ниже 8.3.6. В старых конфигурациях вместо СтрШаблон берут СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку из БСП.
ЗначениеВРеквизитФормы. Метод переносит таблицу в реквизит формы. Колонки реквизита должны быть заданы в конфигураторе с теми же именами, иначе данные в форме не появятся.
Строки обходят циклом Для Каждого или по индексу от 0 до Количество() - 1. Колонки — коллекция Таблица.Колонки, у каждого элемента есть Имя, ТипЗначения, Заголовок. Функция ниже выводит в текст любую таблицу — пригодится для логов:
// Выводит таблицу в текст: строки через перевод строки, значения через табуляцию.
// Работает с любой таблицей - имена колонок берутся из коллекции Колонки.
Функция ТаблицаВТекст(Таблица)
Строки = Новый Массив;
Для Каждого СтрокаТаблицы Из Таблица Цикл
Значения = Новый Массив;
Для Каждого Колонка Из Таблица.Колонки Цикл
Значения.Добавить(Строка(СтрокаТаблицы[Колонка.Имя]));
КонецЦикла;
Строки.Добавить(СтрСоединить(Значения, Символы.Таб));
КонецЦикла;
Возврат СтрСоединить(Строки, Символы.ПС);
КонецФункции
Найти("A-100", "Артикул") возвращает первую строку с таким значением или Неопределено. НайтиСтроки(Отбор) принимает структуру «колонка — значение» и возвращает массив всех подходящих строк. Итог("Сумма") считает сумму по колонке, ВыгрузитьКолонку("Артикул") отдаёт значения колонки массивом — его удобно передать в запрос в условие В (&Артикулы).
Если поиск идёт в цикле по другой таблице, сначала создают индекс по колонкам отбора. Без индекса каждый вызов НайтиСтроки перебирает всю таблицу:
// Заказы: колонки Склад, Артикул, Продано (Число).
// Продажи: таблица из НоваяТаблицаПродаж().
Процедура ЗаполнитьПроданоВЗаказах(Заказы, Продажи)
// Индекс создаётся один раз, до цикла с множеством поисков
Продажи.Индексы.Добавить("Склад, Артикул");
Отбор = Новый Структура("Склад, Артикул");
Для Каждого СтрокаЗаказа Из Заказы Цикл
ЗаполнитьЗначенияСвойств(Отбор, СтрокаЗаказа);
Найденные = Продажи.НайтиСтроки(Отбор); // Массив, пустой, если совпадений нет
СтрокаЗаказа.Продано = 0;
Для Каждого СтрокаПродажи Из Найденные Цикл
СтрокаЗаказа.Продано = СтрокаЗаказа.Продано + СтрокаПродажи.Сумма;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Индекс создают после заполнения таблицы: он обновляется при каждом добавлении строки. Для поиска по одному ключу часто проще собрать соответствие «ключ — строка».
Таблицу передают в запрос параметром, кладут во временную таблицу и соединяют с данными базы. Вместо сотни запросов в цикле выполняется один:
// Сопоставляет артикулы из таблицы с номенклатурой одним запросом.
// Для конфигураций, где у справочника Номенклатура есть реквизит Артикул.
Функция НоменклатураПоАртикулам(Продажи) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Продажи.Артикул КАК Артикул,
| Продажи.Сумма КАК Сумма
|ПОМЕСТИТЬ ВТ_Продажи
|ИЗ
| &Продажи КАК Продажи
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_Продажи.Артикул КАК Артикул,
| ВТ_Продажи.Сумма КАК Сумма,
| Номенклатура.Ссылка КАК Номенклатура
|ИЗ
| ВТ_Продажи КАК ВТ_Продажи
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
| ПО ВТ_Продажи.Артикул = Номенклатура.Артикул";
Запрос.УстановитьПараметр("Продажи", Продажи);
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
У колонок таблицы, которую передают в запрос, должен быть явный тип. Таблица из Выгрузить() типизирована сама, а колонки, созданные вручную, — только если тип указан в Колонки.Добавить. Лишние колонки перед передачей проще отрезать: Продажи.Скопировать(, "Артикул, Сумма").
На форме таблица живёт в реквизите. На сервере его получают через РеквизитФормыВЗначение и возвращают через ЗначениеВРеквизитФормы; для табличной части объекта на форме те же действия выполняют Объект.Товары.Выгрузить() и Объект.Товары.Загрузить(Таблица). Если результат нужен в клиентском коде, возвращают массив структур:
&НаКлиенте
Процедура ПоказатьЛидера(Команда)
Строки = СводкаДляКлиента();
Если Строки.Количество() > 0 Тогда
Лидер = Строки[0];
Сообщить(СтрШаблон("%1, %2: %3", Лидер.Склад, Лидер.Артикул, Лидер.Сумма));
КонецЕсли;
КонецПроцедуры
&НаСервере
Функция СводкаДляКлиента()
Таблица = РеквизитФормыВЗначение("Сводка");
Таблица.Сортировать("Сумма Убыв");
// Возврат Таблица; - так нельзя: таблица значений не передаётся на клиент
Возврат ТаблицыЗначенийСервер.ТаблицаВМассивСтруктур(Таблица);
КонецФункции
| Метод | Что делает | Пример |
|---|---|---|
Колонки.Добавить | Добавляет колонку с именем, типом, заголовком | Т.Колонки.Добавить("Сумма", ТипСумма) |
Колонки.Найти | Возвращает колонку или Неопределено | Т.Колонки.Найти("Сумма") |
Колонки.Удалить | Удаляет колонку | Т.Колонки.Удалить(Колонка) |
Добавить / Вставить | Новая строка в конец / в позицию по индексу | Т.Добавить(), Т.Вставить(0) |
Удалить | Удаляет строку (объект строки или индекс) | Т.Удалить(СтрокаТаблицы) |
Количество | Число строк | Т.Количество() |
Получить / [ ] | Строка по индексу, нумерация с 0 | Т[0] |
Индекс | Номер строки в таблице | Т.Индекс(СтрокаТаблицы) |
Найти | Первая строка со значением или Неопределено | Т.Найти("A-100", "Артикул") |
НайтиСтроки | Массив строк по структуре отбора | Т.НайтиСтроки(Отбор) |
Индексы.Добавить | Индекс для быстрого поиска | Т.Индексы.Добавить("Склад, Артикул") |
Свернуть | Группирует и суммирует, лишние колонки удаляет | Т.Свернуть("Артикул", "Сумма") |
Итог | Сумма по колонке | Т.Итог("Сумма") |
Сортировать | Сортирует по одной или нескольким колонкам | Т.Сортировать("Дата Убыв") |
Скопировать | Новая таблица из части строк и колонок | Т.Скопировать(, "Артикул, Сумма") |
СкопироватьКолонки | Пустая таблица той же структуры | Т.СкопироватьКолонки() |
ВыгрузитьКолонку | Значения колонки массивом | Т.ВыгрузитьКолонку("Артикул") |
ЗагрузитьКолонку | Заполняет колонку из массива по порядку строк | Т.ЗагрузитьКолонку(Цены, "Цена") |
ЗаполнитьЗначения | Пишет одно значение во все строки колонки | Т.ЗаполнитьЗначения(0, "Скидка") |
Сдвинуть | Перемещает строку вверх или вниз | Т.Сдвинуть(СтрокаТаблицы, -1) |
Очистить | Удаляет все строки, колонки остаются | Т.Очистить() |
Сама таблица работает быстро. Тормозит то, как её применяют:
Выгрузить() без условия ГДЕ тащит в память сервера весь регистр. Отбор — в запрос, в таблицу — только нужное.НайтиСтроки внутри цикла по другой таблице на тысячах строк без индекса даёт квадратичный перебор.Новый СравнениеЗначений вторым параметром Сортировать; если нужен алфавит — добавьте колонку с наименованием ещё в запросе.&НаСервере. В реквизите держите только то, что видит пользователь, расчёты ведите в &НаСервереБезКонтекста.Запрос.Выполнить().Выбрать(): выборка обходит уже полученный результат и не строит в памяти вторую полную копию данных, как Выгрузить().Если отчёт уже медленный, начните с замера производительности — о типовых причинах в разделе «1С тормозит».
&НаКлиенте или в клиентском общем модуле. Перенесите код в &НаСервере или &НаСервереБезКонтекста.Свернуть, или её не взял Скопировать.Количество() вместо Количество() - 1 или обращение Т[0] к пустой таблице.Неопределено: колонке не задан тип.Колонки.Добавить.Для Каждого. Нужен обратный цикл.Табличная часть принадлежит объекту и записывается в базу вместе с ним. Таблица значений живёт только в памяти, колонки у неё любые. Между ними данные переносят методами Выгрузить() и Загрузить().
Сравнением типов: ТипЗнч(Значение) = Тип("ТаблицаЗначений"). Так проверяют параметр, который может быть и таблицей, и массивом.
Напрямую — никак. Если данные нужны клиентскому коду, преобразуйте таблицу в массив структур. Чтобы «пронести» таблицу между серверными вызовами, в процедуре &НаСервере положите её во временное хранилище с идентификатором формы: Адрес = ПоместитьВоВременноеХранилище(Таблица, УникальныйИдентификатор). На клиент уходит адрес, при следующем вызове таблицу забирают через ПолучитьИзВременногоХранилища(Адрес). Без второго параметра значение удаляется при очередном вызове сервера.
Для поиска по ключу быстрее и проще соответствие. Для иерархии (группа, подгруппа, позиция) подходит дерево значений: колонки те же, но строки вложены друг в друга. Таблица выигрывает, когда нужны колонки, свёртка, итоги и передача в запрос.
Если таблица значений — часть отчёта или обработки, которая считает неверно или работает минутами, разбор чужого кода обычно занимает больше времени, чем кажется. Такие задачи решает услуга разработки и доработки отчётов и обработок. Опишите, что должно получиться, и разместите задачу на площадке: оценка бесплатная, ответ — в течение рабочего дня.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.