К статье
Практический материал

Разработка и Конфигурация · 10 мин

Как в 1С посчитать количество строк

Как посчитать количество строк в 1С: метод Количество() для табличной части, запрос с ИТОГИ и СУММА, динамический список, СКД. Примеры кода и типичные ошибки.

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

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

Ниже разобраны все основные сценарии с рабочими примерами кода на встроенном языке 1С, указаны ограничения каждого метода и типичные ошибки, из-за которых счётчик показывает неверное значение.

Количество строк табличной части документа

Самая частая задача — узнать, сколько строк в табличной части «Товары», «Услуги» и т.п. У табличной части есть встроенный метод Количество(), который возвращает число строк:

ЧислоСтрок = Объект.Товары.Количество();

Если ЧислоСтрок = 0 Тогда

Сообщить("Документ не содержит товаров");

КонецЕсли;

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

Если нужно посчитать не все строки, а только заполненные по какому-то признаку (например, строки с ненулевым количеством), используйте цикл со счётчиком:

Счетчик = 0;

Для Каждого СтрокаТовара Из Объект.Товары Цикл

Если СтрокаТовара.Количество > 0 Тогда

Счетчик = Счетчик + 1;

КонецЕсли;

КонецЦикла;

Количество строк таблицы значений и результата запроса

Таблица значений — универсальная коллекция для промежуточной обработки данных. У неё тоже есть метод Количество():

ТЗ = Новый ТаблицаЗначений;

// ... заполнение таблицы

ЧислоСтрок = ТЗ.Количество();

Результат запроса после выгрузки — это та же таблица значений, поэтому схема идентична:

РезультатЗапроса = Запрос.Выполнить();

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

ЧислоСтрок = ТаблицаРезультата.Количество();

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

Подсчёт записей в базе через запрос

Когда данные ещё в базе и нужно узнать, сколько записей удовлетворяет условию, используйте агрегатную функцию КОЛИЧЕСТВО:

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| КОЛИЧЕСТВО(*) КАК ЧислоЗаписей

|ИЗ

| Документ.РеализацияТоваровУслуг.Товары КАК Товары

|ГДЕ

| Товары.Ссылка.Дата >= &НачалоПериода";

Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДата()));

Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда

ЧислоСтрок = Выборка.ЧислоЗаписей;

КонецЕсли;

Разница между КОЛИЧЕСТВО(*) и КОЛИЧЕСТВО(Поле) принципиальна: звёздочка считает все строки, а конкретное поле — только строки, где это поле не NULL. Для подсчёта уникальных значений применяется КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Поле) — например, сколько разных номенклатурных позиций встречается в табличной части.

Такой подход быстрее выгрузки, потому что СУБД возвращает одно число вместо тысяч строк. На больших таблицах разница ощутима: выгрузка миллиона записей в таблицу значений может занять десятки секунд и отъесть память, а КОЛИЧЕСТВО(*) отработает за доли секунды.

bsl
ВЫБРАТЬ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Товары.Номенклатура) КАК ЧислоПозиций ИЗ Документ.РеализацияТоваровУслуг.Товары КАК Товары ГДЕ Товары.Ссылка = &Ссылка

Количество строк в динамическом списке на форме

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

Обходные варианты:

  • выполнить отдельный запрос с теми же условиями отбора и функцией КОЛИЧЕСТВО(*) — самый надёжный способ;
  • для произвольной таблицы формы (не динамического списка) использовать Элементы.ТаблицаФормы.Данные либо коллекцию, привязанную к реквизиту формы, и её метод Количество();
  • в управляемой форме для реквизита типа «ТаблицаЗначений» или «ДанныеФормыКоллекция» — прямой вызов Объект.ТаблицаНаФорме.Количество().

Главная ошибка здесь — пытаться перебрать строки динамического списка через Элементы.Список.ТекущиеДанные в цикле. Это невозможно: текущие данные доступны только для активной строки. Если требуется показать пользователю число записей под отбором, выведите на форму отдельный реквизит и заполняйте его запросом при изменении отбора.

Количество строк в отчёте на СКД

В системе компоновки данных подсчёт строк делается ресурсом. Добавьте в набор данных поле-счётчик и определите ресурс с выражением Количество(1) или Количество(Ссылка):

ВЫБРАТЬ

Продажи.Номенклатура КАК Номенклатура,

1 КАК СчетчикСтрок

ИЗ

РегистрНакопления.Продажи.Обороты КАК Продажи

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

Для вывода числа строк в заголовке или подвале отчёта используйте вычисляемое поле или параметр, заполняемый программно в событии ПриКомпоновкеРезультата.

Сравнение способов

Метод Количество() у коллекции

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

КОЛИЧЕСТВО(*) в запросе

Для данных в базе без выгрузки. Быстро на больших объёмах, но требует написания запроса.

Цикл со счётчиком

Когда нужен фильтр по условию в памяти. Гибко, но медленнее на больших коллекциях.

Ресурс СКД

Для отчётов. Считает строки в группировках автоматически, но работает только внутри отчёта.

Проверка результата и типичные ошибки

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

Типичные ошибки
01
КОЛИЧЕСТВО(Поле) вместо КОЛИЧЕСТВО(*) — строки с NULL в поле не учитываются, итог занижен
02
Подсчёт строк табличной части без учёта отбора на форме — пользователь видит отфильтрованные строки, а счётчик показывает все
03
Выгрузка всего результата запроса ради Количество() — лишний расход памяти и времени
04
Попытка получить количество у выборки запроса — у ВыборкаИзРезультатаЗапроса нет такого свойства, нужен обход или Выгрузить()
05
Счётчик в цикле не обнуляется перед повторным использованием — значения накапливаются

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

Контрольные точки

Как проверить результат

Число строк табличной части
Норма

Совпадает с числом видимых строк в документе

Тревожный признак

Счётчик больше — есть скрытые или пустые строки

Результат КОЛИЧЕСТВО(*) в запросе
Норма

Совпадает с числом строк при выгрузке того же запроса без агрегата

Тревожный признак

Меньше — вероятно, использовано КОЛИЧЕСТВО(Поле) с NULL

Счётчик в цикле
Норма

Обнуляется перед каждым новым подсчётом

Тревожный признак

Растёт при повторном вызове процедуры

Часто задаваемые вопросы

Как посчитать количество строк во всех табличных частях документа сразу?

Переберите метаданные документа: для каждой табличной части из Объект.Метаданные().ТабличныеЧасти вызовите Объект[ТЧ.Имя].Количество() и просуммируйте результат. Это удобно для универсальных проверок заполненности.

Можно ли узнать количество строк результата запроса без выгрузки?

Да, двумя способами. Первый — отдельный запрос с КОЛИЧЕСТВО(*) по тем же условиям. Второй — обход выборки циклом Пока Выборка.Следующий() Цикл со счётчиком, но это медленнее и обычно не оправдано.

Почему Количество() возвращает 0, хотя строки на форме видны?

Скорее всего, вы обращаетесь не к той коллекции: например, к объекту на сервере, тогда как строки добавлены в реквизит формы на клиенте и ещё не перенесены. Проверьте, к какому именно реквизиту привязана таблица формы.

Как посчитать строки с учётом отбора, наложенного пользователем на форме?

Для таблицы формы с фиксированными данными пройдите циклом по коллекции и проверяйте условие отбора программно. Для динамического списка сформируйте запрос с теми же параметрами отбора и используйте КОЛИЧЕСТВО(*).

Что быстрее: цикл со счётчиком или НайтиСтроки()?

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

Итог

Что важно запомнить

Для коллекций в памяти — метод Количество(), для данных в базе — запрос с КОЛИЧЕСТВО(*), для отчётов — ресурс СКД. Не выгружайте большие результаты ради подсчёта и помните, что КОЛИЧЕСТВО(Поле) игнорирует NULL.