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

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

Как перебрать все документы в 1С 8: запросы, выборки и перебор видов

Как перебрать все документы в 1С 8: выборка через запрос и метод Выбрать(), обход нескольких видов документов, проведённые и помеченные на удаление. Примеры кода и типичные ошибки.

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

Выбор способа зависит от объёма данных и цели обхода. Если нужно прочитать только ссылку, номер и дату тысяч документов — выгоднее запрос, потому что он не поднимает в память объект целиком. Если по каждому документу нужно изменить табличную часть и записать — удобнее выборка с получением объекта через ПолучитьОбъект().

Отдельная ситуация — перебор документов нескольких видов сразу, например всех документов журнала или всех проведённых документов по регистру. Здесь применяют обход метаданных, объединение запросов или выборку по журналу. Ниже разобраны рабочие примеры кода для каждого сценария, ограничения и типичные ошибки.

Перебор документов одного вида методом Выбрать()

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

Выборка = Документы.РеализацияТоваровУслуг.Выбрать(НачалоГода(ТекущаяДатаСеанса()), КонецГода(ТекущаяДатаСеанса()));

Пока Выборка.Следующий() Цикл

Сообщить(Строка(Выборка.Номер) + " от " + Строка(Выборка.Дата));

КонецЦикла;

Первые два параметра метода — начало и конец периода выборки. Если их не указать, будут выбраны документы за всё время, что на большой базе может занять продолжительное время. Третий параметр позволяет задать отбор по реквизитам, четвёртый — порядок обхода (например, "Дата" или "Номер").

Важно понимать: в цикле вы работаете с выборкой, а не с объектом документа. Чтобы изменить документ, нужно получить объект: ДокОбъект = Выборка.Ссылка.ПолучитьОбъект(). После изменений вызовите ДокОбъект.Записать() с нужным режимом — простая запись или проведение.

bsl
Выборка = Документы.ПоступлениеТоваровУслуг.Выбрать(НачалоМесяца(Период), КонецМесяца(Период));
Пока Выборка.Следующий() Цикл
    ДокОбъект = Выборка.Ссылка.ПолучитьОбъект();
    ДокОбъект.Комментарий = "Обработан пакетно";
    ДокОбъект.Записать();
КонецЦикла;

Перебор документов запросом

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

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Реализация.Ссылка КАК Ссылка,

| Реализация.Номер КАК Номер,

| Реализация.Дата КАК Дата

|ИЗ

| Документ.РеализацияТоваровУслуг КАК Реализация

|ГДЕ

| Реализация.Дата МЕЖДУ &НачалоПериода И &КонецПериода

| И Реализация.Проведен

|

|УПОРЯДОЧИТЬ ПО

| Дата";

Запрос.УстановитьПараметр("НачалоПериода", НачалоГода(ТекущаяДатаСеанса()));

Запрос.УстановитьПараметр("КонецПериода", КонецГода(ТекущаяДатаСеанса()));

Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл

// обработка выборки

КонецЦикла;

Если нужна табличная часть, её можно присоединить прямо в запросе через Документ.РеализацияТоваровУслуг.Товары — это избавляет от получения объекта ради чтения строк. Фильтр Проведен отсекает непроведённые и помеченные на удаление документы, что часто и требуется при анализе учётных данных.

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

Выбор способа перебора

Метод Выбрать()

Подходит для простого обхода одного вида документов с изменением объектов. Ограничение: медленнее запроса при массовом чтении полей.

Запрос к таблице документа

Оптимален для чтения большого числа документов и соединения с табличными частями. Ограничение: для записи всё равно нужен ПолучитьОбъект().

Выборка по журналу

Используется, когда нужно перебрать документы разных видов в общем хронологическом порядке. Ограничение: доступны только поля журнала и графы.

Как перебрать документы всех видов

Когда заранее неизвестен вид документа или нужно обработать все виды сразу, перебирают коллекцию Метаданные.Документы и для каждого вида формируют выборку. Так строят, например, обработки поиска документов по реквизиту или пакетного перепроведения.

Для Каждого МетаДок Из Метаданные.Документы Цикл

Выборка = Документы[МетаДок.Имя].Выбрать(НачалоДня(Период), КонецДня(Период));

Пока Выборка.Следующий() Цикл

// работа с Выборка.Ссылка

КонецЦикла;

КонецЦикла;

Альтернатива — выборка по журналу документов: ЖурналыДокументов.ИмяЖурнала.Выбрать(). Журнал объединяет несколько видов документов в едином списке и возвращает их в хронологическом порядке, что удобно для последовательного перепроведения. Но в выборке журнала доступны только его графы и стандартные поля — специфические реквизиты документа придётся читать через ссылку.

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

Пакетная обработка документов за период
  1. 1
    Определите список видов документов или возьмите все через Метаданные.Документы
  2. 2
    Сформируйте выборку или запрос с отбором по периоду и признаку Проведен
  3. 3
    В цикле получите объект через Ссылка.ПолучитьОбъект() и внесите изменения
  4. 4
    Запишите объект в транзакции, ошибки ловите через Попытка/Исключение и собирайте в список
  5. 5
    По завершении проверьте журнал ошибок и повторите обработку для неудавшихся документов

Отбор по периоду, проведению и пометке удаления

Полный перебор без фильтров почти никогда не нужен. Стандартный набор условий: период (дата документа), признак Проведен и признак ПометкаУдаления. В запросе они задаются в секции ГДЕ, в методе Выбрать() период передаётся параметрами, а остальные условия проверяются в цикле или через отбор.

Логика такова: проведённые документы имеют Проведен = Истина и ПометкаУдаления = Ложь. Помеченные на удаление всегда непроведённые — платформа снимает проведение при установке пометки. Если задача — перепровести учёт, фильтруйте именно по Проведен; если нужно найти «мусор» для удаления — по ПометкаУдаления.

Обращайте внимание на границы периода: КонецДня() и КонецМесяца() возвращают момент 23:59:59, и документы, созданные ровно в последнюю секунду, попадут в выборку корректно. При сравнении в запросе через МЕЖДУ границы включаются, что исключает потерю документов на стыке периодов.

Изменение и перепроведение документов в цикле

Массовая запись документов — самая рискованная часть перебора. Каждый ПолучитьОбъект() загружает документ в память, каждый Записать(РежимЗаписиДокумента.Проведение) выполняет движения по регистрам. На больших объёмах это создаёт нагрузку и может привести к блокировкам, если обработка запущена в рабочее время.

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

ДокОбъект = Выборка.Ссылка.ПолучитьОбъект();

Попытка

ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);

Исключение

Сообщить("Ошибка проведения " + Строка(Выборка.Ссылка) + ": " + ОписаниеОшибки());

КонецПопытки;

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

Производительность и ограничения при больших объёмах

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

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

Для очень больших выборок полезен метод Выбрать() с параметром порядка и обработка результата запроса через Выгрузить() в таблицу значений с обходом по индексу — это даёт контроль над порциями и возможность прервать и возобновить обработку.

Типичные ошибки
01
Вызов ПолучитьОбъект() для каждого документа, когда нужно только прочитать номер и дату — обработка замедляется в разы
02
Запись документа без проверки, изменился ли он — лишние движения и записи в истории изменений
03
Перепроведение без сортировки по дате — некорректные остатки на промежуточные моменты времени
04
Отсутствие Попытка/Исключение в цикле — один проблемный документ останавливает весь пакет
05
Перебор без отбора по периоду на большой базе — долгое выполнение и риск тайм-аута

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

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

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

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

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

Количество документов, удовлетворяющих отбору, до и после обработки
Норма

Совпадает или изменилось ожидаемым образом

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

Часть документов пропущена или появились лишние

Наличие непроведённых документов в обработанном периоде
Норма

Непроведённых нет (кроме осознанно оставленных)

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

Остались документы с ошибками проведения

Список ошибок из Попытка/Исключение
Норма

Пустой или все ошибки разобраны

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

Есть необработанные исключения — документы требуют ручного разбора

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

Чем отличается Выбрать() от запроса при переборе документов?

Метод Выбрать() возвращает выборку с полями документа и подходит для простого обхода одного вида. Запрос выполняется на стороне СУБД, позволяет гибко соединять табличные части и другие таблицы и обычно быстрее при массовом чтении. Для изменения данных в обоих случаях объект получают через Ссылка.ПолучитьОбъект().

Как перебрать только проведённые документы?

В запросе добавьте условие ГДЕ Документ.Проведен — это отсечёт и непроведённые, и помеченные на удаление. При использовании Выбрать() проверяйте свойство Выборка.Проведен внутри цикла и пропускайте документы со значением Ложь.

Как перебрать документы нескольких видов в хронологическом порядке?

Используйте выборку по журналу документов, в который входят нужные виды: ЖурналыДокументов.ИмяЖурнала.Выбрать(). Выборка вернёт документы разных видов, упорядоченные по дате. Если журнала нет, объединяйте результаты запросов по нескольким таблицам через ОБЪЕДИНИТЬ ВСЕ с сортировкой по дате.

Почему в цикле недоступна табличная часть документа?

Выборка содержит только поля шапки документа. Табличную часть можно получить двумя способами: присоединить её в запросе через Документ.ИмяДокумента.ИмяТабличнойЧасти или получить объект через Ссылка.ПолучитьОбъект() — тогда табличные части будут доступны как коллекции строк.

Как безопасно перепровести много документов?

Сделайте резервную копию, протестируйте код на копии базы, проводите документы в порядке возрастания даты, оборачивайте запись каждого документа в Попытка/Исключение и собирайте ошибки в список. На больших объёмах запускайте обработку фоновым заданием в нерабочее время, чтобы не блокировать работу пользователей.

Можно ли прервать и продолжить длинный перебор документов?

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

Итог

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

Для чтения множества документов используйте запрос, для изменения — выборку с ПолучитьОбъект() и записью в транзакции. Все виды документов обходят через Метаданные.Документы или журнал. Фильтруйте по периоду и признаку Проведен, обрабатывайте ошибки по каждому документу, а массовые операции сначала тестируйте на копии базы.