Как узнать количество документов в выборке в 1С:Предприятии 7.7

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При разработке отчетов и сервисных обработок в среде 1С:Предприятие 7.7 разработчики нередко сталкиваются с необходимостью быстро определить количество документов за выбранный период — как в целом, так и в разрезе конкретных видов. Стандартный метод ВыбратьДокументы() возвращает лишь признак того, есть ли в базе хотя бы один документ, соответствующий условию, но не предоставляет готового свойства с общим числом найденных записей. Разберем по шагам, почему так устроена платформа, и рассмотрим оптимальные способы подсчета документов.

Почему метод ВыбратьДокументы() не возвращает количество

Проанализируем внутреннее поведение платформы при вызове метода ВыбратьДокументы(). В 1С 7.7 этот метод инициализирует однонаправленный курсор (forward-only cursor) по таблице документов или соответствующему индексу. Платформа намеренно не выполняет предварительное сканирование всего массива строк и не сохраняет размер выборки в памяти. Это сделано для минимизации потребления оперативной памяти и предотвращения длительных блокировок таблиц базы данных при многопользовательской работе.

Метод возвращает 1, если выборка содержит хотя бы одну запись, и 0, если документов в интервале нет. Чтобы узнать точное число записей непосредственно через объект Документ, программисту приходится обходить выборку последовательно с помощью метода ПолучитьДокумент().

Способ 1. Подсчет через цикл с использованием ВыбратьДокументы()

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


Док = СоздатьОбъект("Документ.Реализация");
КоличествоДокументов = 0;

Если Док.ВыбратьДокументы(НачДата, КонДата) = 1 Тогда
    Пока Док.ПолучитьДокумент() = 1 Цикл
        КоличествоДокументов = КоличествоДокументов + 1;
    КонецЦикла;
КонецЕсли;

Сообщить("Найдено документов Реализация: " + КоличествоДокументов);

Рассмотрим особенности этого подхода: вызов метода ПолучитьДокумент() выполняет полноценное считывание контекста документа из базы. Если за указанный период созданы десятки тысяч документов, чтение шапок через объектную модель вызовет заметную нагрузку на дисковую подсистему и сеть, что существенно замедлит выполнение алгоритма.

Способ 2. Использование штатного механизма запросов (Черный запрос)

Наиболее правильным и универсальным штатным решением является использование встроенного языка запросов 1С 7.7 с агрегатной функцией Счётчик(). Такой подход избавляет от необходимости вручную перебирать документы и считывать их реквизиты в память.

Разберем пример запроса для подсчета документов одного вида:


Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = 
"//{{ЗАПРОС(КоличествоПоВиду)
|Период с НачДата по КонДата;
|ТекущийДок = Документ.Реализация.ТекущийДокумент;
|Функция ВсегоДокументов = Счётчик(ТекущийДок);
|"//}}ЗАПРОС
;

Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    Сообщить("Всего документов: " + Запрос.ВсегоДокументов);
КонецЕсли;

Если же стоит задача подсчитать количество по всем видам документов сразу, не создавая отдельный код для каждого метаданного, применим группировку по виду документа:


Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = 
"//{{ЗАПРОС(КоличествоПоВсемВидам)
|Период с НачДата по КонДата;
|Док = Документ.ТекущийДокумент;
|Группировка Документ.Вид;
|Функция КолДок = Счётчик(Док);
|"//}}ЗАПРОС
;

Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    Пока Запрос.Группировка(1) = 1 Цикл
        Сообщить("Вид документа: " + Запрос.Вид + " - Количество: " + Запрос.КолДок);
    КонецЦикла;
КонецЕсли;

Этот способ работает значительно быстрее циклического перебора объектов, так как агрегация выполняется оптимизированным внутренним механизмом платформы.

Способ 3. Прямое чтение файла журнала 1SJOURN.DBF (для файловых баз)

В файловом режиме работы вся сводная информация о проведенности, дате и идентификаторе вида документа хранится в журнале 1SJOURN.DBF. Поле IDDOCDEF хранит идентификатор вида документа в метаданных, а поле DATE_TIME_IDDOC содержит упакованную дату и время.

Для сверхбыстрого подсчета без загрузки тяжелых объектов 1С можно использовать объект XBase:

  1. Открываем файл 1SJOURN.DBF и подключаем его индекс 1SJOURN.CDX.
  2. Устанавливаем диапазон дат через поиск по составному индексу даты и времени.
  3. Считываем только поле IDDOCDEF и инкрементируем значения в таблице соответствия.

Такой подход обходит модули документов и бизнес-логику платформы, позволяя посчитать сотни тысяч документов за доли секунды.

Способ 4. Прямые запросы к базе данных (для клиент-серверного режима SQL)

Если база данных 1С 7.7 развернута на Microsoft SQL Server, штатные запросы платформы все равно передают часть данных на клиент для формирования выборки. Чтобы получить моментальный результат по количеству документов, целесообразно использовать прямой SQL-запрос через системный объект ADODB.Connection или внешние компоненты прямого доступа.

SQL-запрос вида:


SELECT IDDOCDEF, COUNT(*) AS DocCount 
FROM _1SJOURN 
WHERE DATE_TIME_IDDOC BETWEEN '20230101' AND '20231231Z' 
GROUP BY IDDOCDEF

Данный запрос выполняется силами сервера СУБД непосредственно по индексам таблицы журнала, не нагружает локальную сеть и моментально возвращает результирующий набор, где IDDOCDEF сопоставляется с именем документа через объект метаданных: Метаданные.Документ(НомерВида).Идентификатор.

Итоги и рекомендации

Выбор оптимального метода подсчета зависит от масштаба базы и текущей архитектуры:

  1. Для единичных документов и небольших выборок достаточно стандартного цикла с ВыбратьДокументы() и ПолучитьДокумент().
  2. Для регламентных отчетов и типовых обработок без использования сторонних библиотек лучше всего подходит штатный Запрос с агрегатной функцией Счётчик() и группировкой по видам документов.
  3. Для высоконагруженных систем с миллионными объемами данных максимальную производительность обеспечат чтение 1SJOURN.DBF через XBase (в файловом режиме) или прямые SQL-запросы (в клиент-серверном варианте).
← На главную