Разработка и Конфигурация · 10 мин
Как в 1С посчитать количество строк
Как посчитать количество строк в 1С: метод Количество() для табличной части, запрос с ИТОГИ и СУММА, динамический список, СКД. Примеры кода и типичные ошибки.
Задача подсчитать строки встречается в 1С постоянно: нужно узнать, сколько позиций в табличной части документа, сколько записей вернул запрос, сколько строк выведет отчёт. Проблема в том, что «количество строк» — это разные вещи в разных контекстах, и универсальной кнопки нет. Есть несколько рабочих способов: метод Количество() у коллекций, агрегатные функции в запросе, обход с циклом и счётчиком, а также настройки динамических списков и СКД.
Выбор способа зависит от того, где находятся данные. Если строки уже загружены в табличную часть документа или таблицу значений — достаточно одного вызова метода. Если данные лежат в базе и нужно посчитать записи по условию — правильнее использовать запрос, чтобы не тянуть лишние данные на клиент. Если речь о строках на форме в динамическом списке — потребуется другой подход, потому что динамический список не отдаёт своё содержимое напрямую.
Ниже разобраны все основные сценарии с рабочими примерами кода на встроенном языке 1С, указаны ограничения каждого метода и типичные ошибки, из-за которых счётчик показывает неверное значение.
Количество строк табличной части документа
Самая частая задача — узнать, сколько строк в табличной части «Товары», «Услуги» и т.п. У табличной части есть встроенный метод Количество(), который возвращает число строк:
ЧислоСтрок = Объект.Товары.Количество();
Если ЧислоСтрок = 0 Тогда
Сообщить("Документ не содержит товаров");
КонецЕсли;
Метод работает и на сервере, и на клиенте, не обращается к базе данных и выполняется мгновенно. Это самый дешёвый способ, и его следует предпочитать всегда, когда данные уже открыты на форме или загружены в объект.
Если нужно посчитать не все строки, а только заполненные по какому-то признаку (например, строки с ненулевым количеством), используйте цикл со счётчиком:
Счетчик = 0;
Для Каждого СтрокаТовара Из Объект.Товары Цикл
Если СтрокаТовара.Количество > 0 Тогда
Счетчик = Счетчик + 1;
КонецЕсли;
КонецЦикла;
Количество строк таблицы значений и результата запроса
Таблица значений — универсальная коллекция для промежуточной обработки данных. У неё тоже есть метод Количество():
ТЗ = Новый ТаблицаЗначений;
// ... заполнение таблицы
ЧислоСтрок = ТЗ.Количество();
Результат запроса после выгрузки — это та же таблица значений, поэтому схема идентична:
РезультатЗапроса = Запрос.Выполнить();
ТаблицаРезультата = РезультатЗапроса.Выгрузить();
ЧислоСтрок = ТаблицаРезультата.Количество();
Здесь есть важный нюанс производительности. Если вам нужно только число строк, а сами данные не нужны, выгружать весь результат в память расточительно. Правильнее посчитать строки на стороне СУБД через агрегатную функцию — об этом в следующем разделе. Также учтите: метод Выбрать() возвращает выборку, у которой нет свойства «количество» — число строк можно получить только обходом или через Выгрузить().
Подсчёт записей в базе через запрос
Когда данные ещё в базе и нужно узнать, сколько записей удовлетворяет условию, используйте агрегатную функцию КОЛИЧЕСТВО:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| КОЛИЧЕСТВО(*) КАК ЧислоЗаписей
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК Товары
|ГДЕ
| Товары.Ссылка.Дата >= &НачалоПериода";
Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДата()));
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
ЧислоСтрок = Выборка.ЧислоЗаписей;
КонецЕсли;
Разница между КОЛИЧЕСТВО(*) и КОЛИЧЕСТВО(Поле) принципиальна: звёздочка считает все строки, а конкретное поле — только строки, где это поле не NULL. Для подсчёта уникальных значений применяется КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Поле) — например, сколько разных номенклатурных позиций встречается в табличной части.
Такой подход быстрее выгрузки, потому что СУБД возвращает одно число вместо тысяч строк. На больших таблицах разница ощутима: выгрузка миллиона записей в таблицу значений может занять десятки секунд и отъесть память, а КОЛИЧЕСТВО(*) отработает за доли секунды.
ВЫБРАТЬ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Товары.Номенклатура) КАК ЧислоПозиций ИЗ Документ.РеализацияТоваровУслуг.Товары КАК Товары ГДЕ Товары.Ссылка = &СсылкаКоличество строк в динамическом списке на форме
Динамический список — особый случай. У него нет метода Количество(), потому что список подгружает данные порциями по мере прокрутки и сам не знает точное число строк при сложных отборах. Это осознанное ограничение платформы ради производительности.
Обходные варианты:
- выполнить отдельный запрос с теми же условиями отбора и функцией
КОЛИЧЕСТВО(*)— самый надёжный способ; - для произвольной таблицы формы (не динамического списка) использовать
Элементы.ТаблицаФормы.Данныелибо коллекцию, привязанную к реквизиту формы, и её методКоличество(); - в управляемой форме для реквизита типа «ТаблицаЗначений» или «ДанныеФормыКоллекция» — прямой вызов
Объект.ТаблицаНаФорме.Количество().
Главная ошибка здесь — пытаться перебрать строки динамического списка через Элементы.Список.ТекущиеДанные в цикле. Это невозможно: текущие данные доступны только для активной строки. Если требуется показать пользователю число записей под отбором, выведите на форму отдельный реквизит и заполняйте его запросом при изменении отбора.
Количество строк в отчёте на СКД
В системе компоновки данных подсчёт строк делается ресурсом. Добавьте в набор данных поле-счётчик и определите ресурс с выражением Количество(1) или Количество(Ссылка):
ВЫБРАТЬ
Продажи.Номенклатура КАК Номенклатура,
1 КАК СчетчикСтрок
ИЗ
РегистрНакопления.Продажи.Обороты КАК Продажи
Затем в настройках отчёта пометьте СчетчикСтрок как ресурс с агрегатом «Сумма» — в группировках и общем итоге вы получите число строк в каждой группе. Альтернатива без изменения запроса: ресурс с выражением Количество(Номенклатура), но он не посчитает строки с пустым значением поля.
Для вывода числа строк в заголовке или подвале отчёта используйте вычисляемое поле или параметр, заполняемый программно в событии ПриКомпоновкеРезультата.
Сравнение способов
Для табличных частей и таблиц значений в памяти. Мгновенно, но данные уже должны быть загружены.
Для данных в базе без выгрузки. Быстро на больших объёмах, но требует написания запроса.
Когда нужен фильтр по условию в памяти. Гибко, но медленнее на больших коллекциях.
Для отчётов. Считает строки в группировках автоматически, но работает только внутри отчёта.
Проверка результата и типичные ошибки
После реализации подсчёта сверьте результат с очевидным способом: откройте документ и визуально посчитайте строки, либо выполните тот же запрос в консоли запросов и сравните число с выводом обработки. Расхождение почти всегда означает одну из перечисленных ниже ошибок.
Ещё одна тонкость касается свёрнутых таблиц. Если перед подсчётом таблицу значений свернули методом Свернуть(), строки сгруппированы, и Количество() вернёт число уникальных комбинаций, а не исходное число строк. Проверяйте, в каком состоянии находится коллекция в момент подсчёта.
Как проверить результат
Совпадает с числом видимых строк в документе
Счётчик больше — есть скрытые или пустые строки
Совпадает с числом строк при выгрузке того же запроса без агрегата
Меньше — вероятно, использовано КОЛИЧЕСТВО(Поле) с NULL
Обнуляется перед каждым новым подсчётом
Растёт при повторном вызове процедуры
Часто задаваемые вопросы
Как посчитать количество строк во всех табличных частях документа сразу?
Переберите метаданные документа: для каждой табличной части из Объект.Метаданные().ТабличныеЧасти вызовите Объект[ТЧ.Имя].Количество() и просуммируйте результат. Это удобно для универсальных проверок заполненности.
Можно ли узнать количество строк результата запроса без выгрузки?
Да, двумя способами. Первый — отдельный запрос с КОЛИЧЕСТВО(*) по тем же условиям. Второй — обход выборки циклом Пока Выборка.Следующий() Цикл со счётчиком, но это медленнее и обычно не оправдано.
Почему Количество() возвращает 0, хотя строки на форме видны?
Скорее всего, вы обращаетесь не к той коллекции: например, к объекту на сервере, тогда как строки добавлены в реквизит формы на клиенте и ещё не перенесены. Проверьте, к какому именно реквизиту привязана таблица формы.
Как посчитать строки с учётом отбора, наложенного пользователем на форме?
Для таблицы формы с фиксированными данными пройдите циклом по коллекции и проверяйте условие отбора программно. Для динамического списка сформируйте запрос с теми же параметрами отбора и используйте КОЛИЧЕСТВО(*).
Что быстрее: цикл со счётчиком или НайтиСтроки()?
Если нужно просто число строк по условию, оба способа сопоставимы на небольших таблицах. НайтиСтроки(Отбор).Количество() короче в записи, но создаёт промежуточный массив. На больших таблицах с несколькими подсчётами выгоднее один цикл с несколькими счётчиками.
Что важно запомнить
Для коллекций в памяти — метод Количество(), для данных в базе — запрос с КОЛИЧЕСТВО(*), для отчётов — ресурс СКД. Не выгружайте большие результаты ради подсчёта и помните, что КОЛИЧЕСТВО(Поле) игнорирует NULL.