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

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

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

Как посчитать количество строк в табличной части, таблице значений и результате запроса 1С. Методы Количество(), Итог, запросы, отборы и типичные ошибки.

Задача посчитать количество строк возникает в 1С постоянно: нужно проверить, заполнена ли табличная часть документа, узнать размер таблицы значений перед обходом, определить число записей в справочнике или регистре. Способ подсчёта зависит от того, с каким объектом вы работаете — у каждого типа данных свой инструментарий.

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

Ниже разобраны все рабочие способы с примерами кода, ограничениями каждого подхода и проверкой результата. Примеры актуальны для платформы 1С:Предприятие 8.3 и типовых конфигураций.

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

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

// В модуле объекта или формы документа

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

// Проверка на пустую табличную часть

Если Объект.Товары.Количество() = 0 Тогда

Сообщить("Табличная часть не заполнена");

КонецЕсли;

В модуле менеджера или во внешней обработке, где объект получен через ссылку, сначала получите объект методом ПолучитьОбъект(), и только потом обращайтесь к табличной части:

ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();

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

Учтите важное ограничение: вызов ПолучитьОбъект() загружает весь объект в память. Если нужно узнать количество строк табличной части у тысячи документов, перебор объектов будет медленным — в этом случае правильнее использовать запрос (об этом ниже).

Подсчёт строк в таблице значений

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

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

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

Всего = ТЗ.Количество();

Частая задача — посчитать не все строки, а только те, что удовлетворяют условию. Для этого используется метод НайтиСтроки() с структурой отбора. Метод возвращает массив найденных строк, и его размер — искомое количество:

Отбор = Новый Структура("Склад, Активна", СкладМагазина, Истина);

НайденныеСтроки = ТЗ.НайтиСтроки(Отбор);

КоличествоПоУсловию = НайденныеСтроки.Количество();

Если условие сложное (сравнение «больше», «меньше», «содержит»), НайтиСтроки() не подойдёт — он умеет только равенство. Тогда придётся перебрать таблицу циклом со счётчиком:

Счетчик = 0;

Для Каждого СтрокаТЗ Из ТЗ Цикл

Если СтрокаТЗ.Сумма > 100000 Тогда

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

КонецЕсли;

КонецЦикла;

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

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

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

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

"ВЫБРАТЬ

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

|ИЗ

| Справочник.Номенклатура КАК Номенклатура

|ГДЕ

| НЕ Номенклатура.ПометкаУдаления";

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

Выборка = Результат.Выбрать();

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

КоличествоЭлементов = Выборка.ЧислоЗаписей;

КонецЕсли;

Для подсчёта строк табличной части в разрезе документов обращайтесь напрямую к таблице табличной части:

"ВЫБРАТЬ

| Товары.Ссылка КАК Документ,

| КОЛИЧЕСТВО(*) КАК СтрокВДокументе

|ИЗ

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

|СГРУППИРОВАТЬ ПО

| Товары.Ссылка"

КОЛИЧЕСТВО(*) или КОЛИЧЕСТВО(Поле)

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

Сравнение вариантов

Количество() на коллекции

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

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

Оптимален для данных в базе: справочников, регистров, табличных частей множества документов. Не загружает сами записи.

Перебор выборки со счётчиком

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

Подсчёт строк с условием и группировкой

На практике редко нужно просто общее число — чаще требуется количество по категориям: строк по каждому складу, документов по каждому контрагенту. В запросе это решается группировкой, как в примере выше. В таблице значений — свёрткой или сводной обработкой.

Для таблицы значений удобен приём с соответствием: ключ — значение группировки, значение — счётчик:

КоличествоПоСкладам = Новый Соответствие;

Для Каждого СтрокаТЗ Из ТЗ Цикл

Текущее = КоличествоПоСкладам[СтрокаТЗ.Склад];

КоличествоПоСкладам[СтрокаТЗ.Склад] = ?(Текущее = Неопределено, 1, Текущее + 1);

КонецЦикла;

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

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

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

Для табличного поля, связанного с таблицей значений на форме (реквизит формы типа «ТаблицаЗначений»), всё проще — обращайтесь к реквизиту формы и вызывайте Количество():

// В модуле управляемой формы

СтрокВТаблице = ЭтаФорма.ТаблицаДанных.Количество();

Если нужно показать пользователю число строк с учётом наложенного им отбора в табличном документе или списке, проще всего сформировать отчёт на СКД с ресурсом «Количество» — система сама посчитает итог с учётом всех отборов.

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

Производительность и ограничения

Главное правило: никогда не считайте записи перебором выборки, если нужно только число. Код вида «выбрать все документы и в цикле делать Счетчик = Счетчик + 1» заставляет сервер передать клиенту все записи целиком. На таблице в несколько сотен тысяч записей разница между перебором и КОЛИЧЕСТВО(*) — секунды против минут.

Второй риск — подсчёт строк табличных частей через ПолучитьОбъект() в цикле. Каждый вызов читает объект целиком, включая все табличные части и движения при последующей записи. Для массовой обработки всегда заменяйте такой код запросом к таблице табличной части.

Ограничение метода НайтиСтроки() — только сравнение на равенство и необходимость точного совпадения типов: отбор по строке «001» не найдёт значение, если в колонке хранится число 1. При несовпадении типов метод молча вернёт пустой массив, и вы получите ноль без какой-либо ошибки.

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

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

Типичные ошибки
01
Перебор выборки циклом ради подсчёта — на больших таблицах работает в разы медленнее КОЛИЧЕСТВО(<em>)
02
Отбор в НайтиСтроки() с несовпадающим типом значения — метод возвращает пустой массив без ошибки, и логика молча работает с нулём
03
КОЛИЧЕСТВО(Поле) вместо КОЛИЧЕСТВО(</em>) — строки с незаполненным полем не учитываются, итог занижен
04
Обращение к табличной части через ссылку без ПолучитьОбъект() — у объекта ДокументСсылка нет доступа к строкам табличной части
05
Подсчёт строк динамического списка обходом видимых строк — список подгружается порциями, и результат будет неполным

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

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

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

Пустая таблица или отбор без совпадений
Норма

Возвращается 0, ошибок нет

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

Возникает исключение или Неопределено вместо числа

Запрос с соединением таблиц
Норма

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

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

Число завышено кратно числу связанных записей

НайтиСтроки() с отбором
Норма

Найдено столько строк, сколько видно при ручном фильтре

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

Возвращён пустой массив при заведомо существующих данных — проверьте типы значений

Частые вопросы

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

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

Чем отличается Количество() у таблицы значений от обхода циклом?

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

Почему НайтиСтроки() возвращает пустой массив, хотя данные есть?

Чаще всего причина в несовпадении типов: в отборе указана строка, а в колонке хранится число или ссылка. Метод сравнивает строго на равенство и не сообщает об ошибке — проверьте типы значений в отборе и в колонке таблицы.

Как посчитать количество разных значений в колонке?

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

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

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

Что быстрее: запрос или перебор выборки для подсчёта?

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

Итог

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

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