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