1C-CodeОсновы 1С → Таблица значений

Таблица значений

Коллекция, которой в 1С пользуются чаще массива. Колонки, строки, поиск, свёртка и итоги — и почему её нельзя отдать на клиент.

Глава 34 из 36 · чтение примерно 26 минут

Массив хранит список значений. Соответствие — пары ключ-значение. А таблица значений хранит строки с колонками — то есть ровно то, чем в учётной работе оказывается почти всё: строки документа, результат запроса, промежуточный расчёт.

Поэтому она встречается чаще остальных коллекций вместе взятых.

Создать и заполнить

Т = Новый ТаблицаЗначений;
Т.Колонки.Добавить("Товар");
Т.Колонки.Добавить("Сумма");
Строка = Т.Добавить();
Строка.Товар = "Гвозди";
Строка.Сумма = 120;
ЧастьЧто означает
Новый ТаблицаЗначенийпустая таблица без колонок
Колонки.Добавитьколонки заводят до строк, иначе писать некуда
Т.Добавить()добавляет строку и ВОЗВРАЩАЕТ её — сразу заполняем
Строка.Товар =к полям строки обращаются по имени колонки

Что она умеет сама

Большая часть работы с таблицей — это не циклы, а её собственные методы. Писать цикл там, где есть метод, — и дольше, и медленнее.

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

Свернуть — самый полезный метод

Т.Свернуть("Товар", "Сумма") превращает десять строк по одному товару в одну со сложенной суммой.

Это ровно то, что в запросе делает СГРУППИРОВАТЬ ПО, только для таблицы, которая уже в памяти. Перед соединением или выводом свёртка часто убирает половину строк — и заодно половину проблем с дублями.

Откуда таблицы берутся

Руками их создают реже, чем получают готовыми:

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

Скопировать с параметрами умеет сразу отобрать строки и оставить нужные колонки — часто это дешевле, чем цикл с удалением.

На чём спотыкаются

Удаляют строки в цикле «Для Каждого». После удаления обход сбивается и часть строк пропускается. Удалять надо с конца — от последней строки к первой. Обратного Для в 1С нет, поэтому пишут Сч = Т.Количество() - 1; Пока Сч >= 0 Цикл … Сч = Сч - 1;: подробно это разобрано в главе про коллекции.

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

Складывают строки циклом вместо Итог и Свернуть. Работает, но длиннее и медленнее — а на большой таблице заметно.

Забывают, что Добавить возвращает строку. Пишут Т.Добавить(); Строка = Т[Т.Количество()-1]; — то же самое в три раза длиннее.

Упражнение 1. Итог по таблице

Функция ИтогПоСтрокам(Суммы) получает массив чисел, складывает их в таблицу значений с одной колонкой Сумма и возвращает итог по этой колонке — методом Итог, а не циклом.

Решается в тренажёре: код запускается и проверяется сразу.

Колонка без типа принимает что угодно

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

Дальше начинается то, что ищут полдня: Итог("Сумма") падает, потому что в одной строке оказалась строка «120» вместо числа; сортировка выстраивает числа как текст, и 9 оказывается больше 100; сравнение с нулём не срабатывает, потому что там Неопределено.

Поэтому колонке задают тип.

Колонки с типами

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

Строка = Т.Добавить();   // Количество уже 0, а не Неопределено
ЧастьЧто означает
Новый ОписаниеТипов("Число")описание типа колонки — второй параметр Добавить
Количество уже 0у типизированной колонки есть пустое значение: 0, пустая строка, пустая дата
Неопределеноа в нетипизированной новая ячейка именно такая — и любая арифметика по ней падает

Откуда типы берутся сами

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

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

Найти нужные строки

Два метода, и путают их постоянно.

НайтиСтроки(Отбор)все строки, подходящие под отбор. Отбор задаётся структурой «колонка → значение», условий может быть несколько. Возвращает массив: не нашлось — массив пустой, проверять надо Количество() = 0, а не сравнение с Неопределено.

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

Найденная строка — та же самая строка

НайтиСтроки возвращает не копии, а ссылки на строки самой таблицы. Написали Найденная.Сумма = 0 — изменилась таблица.

Это рабочий приём: найти строку по отбору и поправить её на месте, без индексов и циклов. И это же ловушка, когда правку не задумывали: «я же работал с результатом поиска, откуда изменения в таблице».

Упражнение 2. Сумма по складу

Напишите СуммаСклада(Т, Склад): таблица с колонками Товар, Склад, Сумма. Верните сумму строк указанного склада — через НайтиСтроки, а не перебором всей таблицы. Проверка спрашивает про «Основной» и ждёт 2550.

Решается в тренажёре: код запускается и проверяется сразу.

Свёртка: что она делает с колонками

Т.Свернуть("Товар", "Сумма") — два аргумента, и оба списки колонок через запятую: по чему группировать и что складывать.

Главное, чего не ждут: колонки, не попавшие ни в первый список, ни во второй, из таблицы исчезают. Была таблица с товаром, складом и суммой, свернули по товару с суммой — колонки «Склад» больше нет. Не «стала пустой», а нет: обращение к ней падает.

Это логично — склад у схлопнутых строк был разный, и выбрать один невозможно, — но узнают об этом обычно из ошибки.

Свернуть, Сортировать и Удалить меняют саму таблицу

Они ничего не возвращают. Новая = Т.Свернуть(…) не сработает: Новая окажется Неопределено, а исходная таблица будет уже свёрнута.

Когда исходная нужна целой, работают с копией: К = Т.Скопировать(); и сворачивают уже её. Особенно это важно, когда таблицу вам передали в параметре — она чужая, и свернув её, вы испортите данные вызывающему.

Упражнение 3. Сколько разных товаров

Напишите СколькоТоваров(Т): сколько различных товаров встречается в таблице. Сделайте это свёрткой копии — исходная таблица должна остаться целой. В проверке четыре строки и три разных товара.

Решается в тренажёре: код запускается и проверяется сразу.

Упражнение 4. Самый дорогой товар

Напишите СамыйДорогой(Т): верните название товара с наибольшей суммой по всем складам. Сложите суммы свёрткой, отсортируйте по убыванию и возьмите первую строку. Ответ проверки — Гвозди.

Решается в тренажёре: код запускается и проверяется сразу.

Копия, отбор и урезание в одну строку

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

Три способа скопировать

К = Т.Скопировать();                                   // всё целиком
К = Т.Скопировать(Новый Структура("Склад", Склад));    // только строки склада
К = Т.Скопировать(, "Товар, Сумма");                   // только две колонки
К = Т.Скопировать(Отбор, "Товар, Сумма");              // и то, и другое
ЧастьЧто означает
Скопировать()новая таблица с теми же строками; менять её можно свободно
Новый Структура("Склад", Склад)отбор — та же структура, что у НайтиСтроки
, "Товар, Сумма"запятая на месте пропущенного отбора — колонки идут вторым аргументом
короче циклато же самое циклом с Удалить — десять строк и шанс ошибиться в индексах

Колонка как массив

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

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

Обратный метод — ЗагрузитьКолонку(Массив, "Имя"): записывает значения массива в колонку по порядку. Встречается редко, но в чужом коде попадается.

Когда таблица большая

НайтиСтроки перебирает таблицу целиком. На сотне строк это незаметно, на десятках тысяч — и особенно внутри цикла — превращается в минуты.

В настоящей 1С у таблицы есть индексы: Т.Индексы.Добавить("Товар") — и поиск по этой колонке идёт сразу к нужным строкам. Наш браузерный движок индексов не изображает, поэтому упражнения на них нет; знать про них всё равно нужно — про них спрашивают.

И более общий приём: если ищете по таблице много раз, разложите её один раз в соответствие «ключ → строка». Тот же способ, что в главе про коллекции.

Почему её нельзя отдать на клиент

Это спрашивают на собеседованиях, и ответ «потому что серверный тип» неполный.

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

Что делают вместо этого:

Массив структур — когда данных немного и они нужны коду. Сериализуется, передаётся, читается так же.

Реквизит формы типа ТаблицаЗначений — когда данные нужно показать. На форме таблица живёт законно, а обмен с сервером делают ЗначениеВРеквизитФормы и РеквизитФормыВЗначение.

Адресное хранилище — когда таблица большая и её надо просто «пронести» через клиент, не читая: положили на сервере, передали адрес, забрали на сервере.

ЗначениеВСтрокуВнутр — не способ

В старом коде встречается передача через ЗначениеВСтрокуВнутр: таблица превращается в строку, едет на клиент и там разворачивается обратно.

Формат этой строки не описан и меняется между версиями платформы. Хранить её в базе нельзя, разбирать нельзя, на совместимость рассчитывать нельзя. Для передачи есть три способа выше — они и предназначены для этого.

Родственники

У таблицы есть два ближайших родственника, которые встречаются реже, но узнавать их надо.

ДеревоЗначений — та же таблица, но у строк есть подчинённые строки (Строка.Строки). Так показывают иерархию: группы и элементы, итоги и детали отчёта.

ТаблицаЗначений на форме — это уже не она, а данные формы: у них свои типы и своё поведение, и напрямую методы таблицы там не работают. Отсюда и РеквизитФормыВЗначение: получить настоящую таблицу, поработать, положить обратно.

Короткий свод

Таблица значений — строки с колонками, самая частая коллекция в 1С. Колонки заводят до строк; Добавить() сразу возвращает строку. Итог, Свернуть, НайтиСтроки, Сортировать делают работу за вас — цикл нужен реже, чем кажется. Удалять строки обходом «Для Каждого» нельзя. На клиент таблицу не передать: это серверный тип.

Как закрепить

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

Открыть эту главу в тренажёре

Обмен данными и интеграции
Ошибки и исключения