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