Как выбрать документы за период в 1С и почему выборка возвращает только один документ

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с объектами платформы 1С разработчики часто сталкиваются с ситуацией, когда метод менеджера объекта Выбрать() возвращает только один документ вместо ожидаемого списка за период (например, за последние 40 дней). Проанализируем причины такого поведения и разберем правильные способы решения этой задачи.

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

Рассмотрим распространенный пример кода, с помощью которого совершается попытка получить документы за последние 40 дней:


Выборка = Документы.ЗаказТоваров.Выбрать(НачалоДня(ТекущаяДата() - 86400 * 40), КонецДня(ТекущаяДата()));

Часто после выполнения этой строки разработчик обращается непосредственно к объекту Выборка и видит данные только последнего документа. Причина заключается в особенности работы платформы с выборками данных.

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

Разберем по шагам правильный алгоритм обхода выборки:

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

Посмотрим на пример правильной работы с выборкой объектов:


ДатаНачала = НачалоДня(ТекущаяДатаСеанса() - 86400 * 40);
ДатаОкончания = КонецДня(ТекущаяДатаСеанса());

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

Альтернативное и более эффективное решение: выборка через запрос

Использование метода Выбрать() объекта ДокументыМенеджер в коде на платформе 1С не всегда является оптимальным решением. При обработке больших массивов данных выборка создает лишнюю нагрузку на сервер приложения и базу данных.

Проанализируем решение той же задачи с помощью языка запросов 1С. Запрос выбирает исключительно необходимые поля и позволяет максимально эффективно использовать индексы базы данных.

Для гарантированного попадания в индекс по полю Дата рекомендуется использовать конструкцию с оператором МЕЖДУ:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ЗаказТоваров.Ссылка КАК Ссылка,
    |	ЗаказТоваров.Дата КАК Дата
    |ИЗ
    |	Документ.ЗаказТоваров КАК ЗаказТоваров
    |ГДЕ
    |	ЗаказТоваров.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
    |УПОРЯДОЧИТЬ ПО
    |	Дата";

Запрос.УстановитьПараметр("ДатаНачала", НачалоДня(ТекущаяДатаСеанса() - 86400 * 40));
Запрос.УстановитьПараметр("ДатаОкончания", КонецДня(ТекущаяДатаСеанса()));

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

Пока Выборка.Следующий() Цикл
    // Обработка результатов запроса
КонецЦикла;

Также условия выборки в самом тексте запроса можно построить с применением функции языка запросов ДОБАВИТЬКДАТЕ:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ЗаказТоваров.Ссылка КАК Ссылка,
    |	ЗаказТоваров.Дата КАК Дата
    |ИЗ
    |	Документ.ЗаказТоваров КАК ЗаказТоваров
    |ГДЕ
    |	ЗаказТоваров.Дата >= ДОБАВИТЬКДАТЕ(&ТекущаяДата, ДЕНЬ, -40)
    |УПОРЯДОЧИТЬ ПО
    |	Дата";

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

Рекомендации по оптимизации и работе с датами

При написании кода выборки документов следует учитывать следующие практические нюансы:

  1. Используйте ТекущаяДатаСеанса() вместо ТекущаяДата(): В клиент-серверном варианте работы системная дата сервера и дата клиента могут отличаться из-за разных часовых поясов. Метод ТекущаяДатаСеанса() возвращает точную дату с учетом настроек сеанса пользователя.
  2. Задавайте четкие границы интервала: При фильтрации документов всегда приводите начальную дату к НачалоДня(), а конечную — к КонецДня(), чтобы не потерять документы, созданные в течение текущего дня.
  3. Количество секунд в дне: При смещении дат в коде стандартное значение составляет 86 400 секунд (60 * 60 * 24).
  4. Ограничения RLS: Если у пользователя действуют ограничения прав на уровне записей, метод .Выбрать() может не вернуть документы, к которым у пользователя нет доступа. При работе через запрос с использованием ВЫБРАТЬ РАЗРЕШЕННЫЕ платформа корректно отсечет недоступные данные без ошибок.
← На главную