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