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