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

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

Как получить количество строк в динамическом списке 1С

Способы получить количество строк динамического списка в 1С: через СКД, временную таблицу, пакетный запрос. Ограничения, типичные ошибки и примеры кода.

Динамический список в 1С не хранит данные на клиенте: он выполняет запрос к базе и показывает результат порциями по мере прокрутки. Поэтому привычного свойства «КоличествоСтрок» у таблицы формы с динамическим списком нет — платформа сама не знает итоговое число записей, пока не выполнит запрос целиком.

Чтобы узнать количество строк, нужно выполнить тот же запрос, что формирует список, но с агрегатной функцией КОЛИЧЕСТВО. При этом важно учесть отборы, которые пользователь установил в настройках списка, иначе число не будет совпадать с тем, что видно на экране.

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

Почему у динамического списка нет готового счетчика строк

Динамический список оптимизирован для работы с большими таблицами. При включенном динамическом считывании платформа подгружает данные небольшими порциями по мере прокрутки, и полный объем выборки нигде не материализуется. Даже на сервере нет объекта, у которого можно спросить «сколько всего строк».

Стандартный элемент отображения данных внизу списка показывает позицию текущей строки и приблизительное общее число записей, но это значение платформа получает отдельным служебным запросом и программно к нему не обращаются. Для прикладной логики — например, чтобы вывести «Найдено записей: 154» или заблокировать кнопку при пустом списке — нужен собственный запрос.

Способ 1. Запрос с КОЛИЧЕСТВО по тексту запроса списка

Самый простой вариант — взять текст запроса динамического списка, обернуть его во вложенный запрос и посчитать строки. Это работает, когда у списка задан произвольный запрос и отборы применяются через параметры.

bsl
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| КОЛИЧЕСТВО(*) КАК КоличествоСтрок
|ИЗ
| (" + Список.ТекстЗапроса + ") КАК ВложенныйЗапрос";

Для Каждого Параметр Из Список.Параметры Цикл
    Запрос.УстановитьПараметр(Параметр.Имя, Параметр.Значение);
КонецЦикла;

Выборка = Запрос.Выполнить().Выбрать();
Выборка.Следующий();
КоличествоСтрок = Выборка.КоличествоСтрок;

Ограничение метода очевидно: отборы, которые пользователь установил через настройки списка (стандартные отборы СКД), в ТекстЗапроса не попадают. Если пользователь отфильтровал список по контрагенту, ваш запрос посчитает все записи без учета этого фильтра. Для списков с пользовательскими отборами нужен способ через СКД.

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

Способ 2. Подсчет через схему компоновки данных

Корректный универсальный способ — выполнить компоновку данных с теми же настройками, что у списка, и получить результат в таблицу значений или сразу итоговый запрос. Динамический список внутри себя использует именно СКД, поэтому этот путь гарантирует совпадение с тем, что видит пользователь.

Порядок действий
  1. 1
    Получите схему компоновки данных списка через Список.ПолучитьИсполняемуюСхемуКомпоновкиДанных()
  2. 2
    Получите исполняемые настройки: Список.ПолучитьИсполняемыеНастройкиКомпоновкиДанных()
  3. 3
    Создайте компоновщик макета и сформируйте макет с типом ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений
  4. 4
    Выполните процессор компоновки и выведите результат в таблицу значений через процессор вывода
  5. 5
    Количество строк — это ТаблицаРезультата.Количество()

Пример кода на серверной процедуре формы:

bsl
&НаСервере
Функция КоличествоСтрокСписка()

    Схема = Список.ПолучитьИсполняемуюСхемуКомпоновкиДанных();
    Настройки = Список.ПолучитьИсполняемыеНастройкиКомпоновкиДанных();

    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    Макет = КомпоновщикМакета.Выполнить(Схема, Настройки, , ,
        Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));

    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(Макет);

    Результат = Новый ТаблицаЗначений;
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
    ПроцессорВывода.УстановитьОбъект(Результат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);

    Возврат Результат.Количество();

КонецФункции

Методы ПолучитьИсполняемуюСхемуКомпоновкиДанных и ПолучитьИсполняемыеНастройкиКомпоновкиДанных возвращают именно то, что платформа использует для выборки: с учетом отборов пользователя, параметров и настроек порядка. Это ключевое преимущество перед ручной сборкой запроса.

Способ 3. Пакетный запрос с временной таблицей

Если список построен на сложном произвольном запросе, а выводить все данные в память нежелательно, используйте пакетный запрос: первая часть помещает результат в временную таблицу, вторая считает строки в ней. Так на клиент и в память сервера возвращается одно число, а не вся выборка.

bsl
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
| Док.Ссылка КАК Ссылка
|ПОМЕСТИТЬ ВТ_Список
|ИЗ Документ.РеализацияТоваровУслуг КАК Док
|ГДЕ Док.Контрагент = &Контрагент
|;
|ВЫБРАТЬ
| КОЛИЧЕСТВО(*) КАК КоличествоСтрок
|ИЗ ВТ_Список КАК ВТ";
Запрос.УстановитьПараметр("Контрагент", Контрагент);
Количество = Запрос.Выполнить().Выбрать();

Первый запрос пакета должен повторять логику отборов списка. Если отборы задаются динамически, удобнее извлечь их из настроек компоновки и транслировать в параметры — иначе при изменении логики списка придется синхронно править два места в коде, что рано или поздно приведет к расхождению чисел.

Выбор способа под вашу задачу

Каждый из трех подходов имеет свою область применения. Сводная таблица поможет быстро определиться.

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

Как выбрать действие

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

Производительность и безопасная реализация

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

Практичные решения: считать количество по кнопке «Обновить счетчик», при изменении отборов с небольшой задержкой через подключаемый обработчик ожидания либо в фоновом задании с выводом результата в надпись на форме. Для списков документов среднего объема обычно достаточно пересчета при изменении отборов.

Не выполняйте подсчет в обработчике ПриАктивизацииСтроки — он срабатывает при каждом перемещении курсора и превратит работу со списком в череду запросов к базе.

Типичные ошибки
01
Попытка обратиться к Элементы.Список.ТекущиеДанные.Количество() или искать свойство количества у таблицы формы — такого API нет, динамический список не коллекция
02
Подсчет без учета пользовательских отборов — число на форме не совпадает с видимым списком, пользователи теряют доверие к счетчику
03
Отсутствие РАЗРЕШЕННЫЕ в запросе — при RLS счетчик показывает больше строк, чем доступно пользователю
04
КОЛИЧЕСТВО(*) вместо КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Ссылка) при соединениях — дубли завышают результат
05
Пересчет на каждое событие списка — лишняя нагрузка на СУБД и заметные задержки интерфейса

Проверка результата

После внедрения счетчика убедитесь, что число совпадает с реальным содержимым списка в разных режимах.

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

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

Список без отборов
Норма

Счетчик равен числу записей по прямому запросу к таблице

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

Счетчик меньше — вероятно, лишнее условие в запросе подсчета

Список с пользовательским отбором
Норма

Число меняется и соответствует видимым строкам

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

Число не меняется — отборы настроек не учитываются

Пользователь с ограниченными правами (RLS)
Норма

Счетчик равен количеству доступных записей

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

Счетчик больше видимых строк — нет РАЗРЕШЕННЫЕ

Список с соединениями в запросе
Норма

Дубли не влияют на итог

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

Число завышено — нужен РАЗЛИЧНЫЕ по ключу

Простой ручной тест: установите отбор так, чтобы в списке осталось несколько строк, посчитайте их визуально и сравните со счетчиком. Затем снимите отбор и проверьте поведение на полном объеме — время выполнения не должно превышать комфортное для пользователя.

Итог

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

У динамического списка нет встроенного счетчика строк — количество получают отдельным запросом. Для точного совпадения с экраном используйте исполняемую СКД списка, для больших выборок — пакетный запрос с КОЛИЧЕСТВО, и всегда учитывайте отборы пользователя и права доступа.

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

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

Нет. Динамический список не материализует полный результат, поэтому единственный способ узнать число записей — выполнить агрегатный запрос к базе. Приблизительное значение из служебной строки состояния программно недоступно.

Почему счетчик не совпадает с количеством видимых строк?

Чаще всего не учтены отборы из настроек списка, отсутствует ключевое слово РАЗРЕШЕННЫЕ при действующем RLS или запрос содержит соединения, дающие дубли. Проверяйте подсчет на исполняемых настройках СКД и используйте КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Ссылка).

Как посчитать строки, если список использует основную таблицу без произвольного запроса?

Платформа сама строит запрос по основной таблице. Либо сформируйте свой запрос к этой таблице с теми же отборами, либо используйте методы ПолучитьИсполняемуюСхемуКомпоновкиДанных и ПолучитьИсполняемыеНастройкиКомпоновкиДанных — они работают и для непроизвольных списков.

Где разместить код подсчета — на клиенте или на сервере?

Только на сервере: запросы к базе выполняются в серверном контексте. Обычно создают серверную функцию формы, возвращающую число, а клиентская процедура лишь вызывает её и выводит результат в надпись или заголовок.

Как показать счетчик, не замедляя открытие формы?

Не считайте при создании формы. Запускайте подсчет в фоновом задании после открытия или по явной команде пользователя, а результат выводите в декорацию-надпись рядом со списком. При изменении отборов обновляйте счетчик с задержкой через ПодключитьОбработчикОжидания.

Работает ли подсчет через СКД в мобильной платформе и веб-клиенте?

Механизм компоновки данных доступен на сервере независимо от клиента, поэтому серверная функция подсчета работает и для тонкого, и для веб-клиента. Ограничения могут касаться только фоновых заданий в файловом режиме — там длительные операции блокируют сеанс.