Как подсчитать количество заполненных ячеек в диапазоне колонок Таблицы Значений?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С часто возникает задача анализа данных, представленных в виде Таблицы Значений (ТЗ), где колонки соответствуют определенным периодам, например, дням месяца. Рассмотрим ситуацию, когда у нас есть таблица с 31 колонкой (дни), и нам необходимо вычислить, сколько ячеек заполнены данными в конкретном интервале (например, с 5-го по 15-й день).

Разберем по шагам различные подходы к решению этой задачи: от простого перебора по индексам до более гибких методов с использованием динамических имен колонок и оптимизацией производительности.

Способ 1: Обращение к колонкам по их индексу

Если структура вашей таблицы жестко зафиксирована и вы точно знаете порядковые номера колонок, самый простой способ — использовать метод Получить() для объекта СтрокаТаблицыЗначений. Проанализируем, как организовать такой цикл:


// Задаем границы диапазона индексов колонок
Начало = 5; // Индекс 5 соответствует 6-й колонке (индексация с 0)
Конец = 15; 

ОбщееКоличествоЗаполненных = 0;

Для Каждого СтрокаТЗ Из ТаблицаЗначений Цикл
    Для Сч = Начало По Конец Цикл
        // Получаем значение ячейки по индексу
        ЗначениеЯчейки = СтрокаТЗ.Получить(Сч);
        
        // Проверяем, заполнено ли значение
        Если ЗначениеЗаполнено(ЗначениеЯчейки) Тогда
            ОбщееКоличествоЗаполненных = ОбщееКоличествоЗаполненных + 1;
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

Сообщить("Всего заполнено ячеек в диапазоне: " + ОбщееКоличествоЗаполненных);

Важное замечание: Индексация колонок в 1С начинается с нуля. Если ваша таблица содержит только 31 колонку дней (без дополнительных колонок типа "Номенклатура" или "Сотрудник" в начале), то 5-й индекс будет соответствовать 6-му числу месяца.

Способ 2: Использование динамических имен колонок

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


НачальныйДень = 5;
КонечныйДень = 15;
ИтогЗаполненных = 0;

Для Каждого ТекущаяСтрока Из ТаблицаЗначений Цикл
    Для НомерДня = НачальныйДень По КонечныйДень Цикл
        // Формируем имя колонки программно
        ИмяКолонки = "День_" + Формат(НомерДня, "ЧГ=0");
        
        // Проверяем наличие колонки в таблице для исключения ошибок
        Если ТаблицаЗначений.Колонки.Найти(ИмяКолонки) <> Неопределено Тогда
            Если ЗначениеЗаполнено(ТекущаяСтрока[ИмяКолонки]) Тогда
                ИтогЗаполненных = ИтогЗаполненных + 1;
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

Способ 3: Оптимизация через предварительный сбор имен колонок

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

Рассмотрим алгоритм оптимизации:

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

// 1. Подготовка списка колонок
МассивИмен = Новый Массив;
Для НомерДня = 5 По 15 Цикл
    МассивИмен.Добавить("День_" + Формат(НомерДня, "ЧГ=0"));
КонецЦикла;

// 2. Основной расчет
Всего = 0;
Для Каждого Стр Из ТаблицаЗначений Цикл
    Для Каждого ИмяКол Из МассивИмен Цикл
        Если ЗначениеЗаполнено(Стр[ИмяКол]) Тогда
            Всего = Всего + 1;
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

Нюансы использования функции ЗначениеЗаполнено()

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

Альтернативный подход: Использование метода Итог()

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

Метод ТаблицаЗначений.Итог("ИмяКолонки") реализован на уровне платформы и работает значительно быстрее, чем цикл Для Каждого. Если в ваших колонках хранятся числа 1 (заполнено) и 0 (пусто), код будет выглядеть так:


ОбщийИтог = 0;
Для НомерДня = 5 По 15 Цикл
    ИмяКолонки = "День_" + НомерДня;
    ОбщийИтог = ОбщийИтог + ТаблицаЗначений.Итог(ИмяКолонки);
КонецЦикла;

Работа с большими данными через Запрос

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

Разберем этот механизм:

  1. Передаем ТЗ как параметр в запрос (используя временные таблицы).
  2. В тексте запроса суммируем нужные поля.
  3. Получаем результат одним числом.

Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст = "ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Данные ИЗ &ТЗ КАК ТЗ;
               |ВЫБРАТЬ СУММА(День_5 + День_6 + ... + День_15) КАК Итого ИЗ ВТ_Данные";
Запрос.УстановитьПараметр("ТЗ", ТаблицаЗначений);
РезультатЗапроса = Запрос.Выполнить().Выгрузить();

Подводя итог, выбор метода зависит от конкретной архитектуры вашего решения. Для быстрой разработки при небольших объемах данных идеально подходит Способ 1 или Способ 2. Если же важна надежность и производительность — стоит смотреть в сторону предварительного кэширования имен колонок или использования методов Итог() и запросов.

← На главную