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