Как правильно выбрать документы «Заказ покупателя» из регистра накопления в 1С?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

Проанализируем исходные варианты запросов, с которыми возникли сложности:

Прямой запрос к документам:


ВЫБРАТЬ
    ЗаказПокупателя.Ссылка
ИЗ
    Документ.ЗаказПокупателя КАК ЗаказПокупателя
ГДЕ
    ЗаказПокупателя.Дата МЕЖДУ &НачДата И &КонДата

Запрос к виртуальной таблице регистра:


ВЫБРАТЬ
    ЗаказыПокупателейОстаткиИОбороты.ЗаказПокупателя.Ссылка
ИЗ
    РегистрНакопления.ЗаказыПокупателей.ОстаткиИОбороты(&НачДата, &КонДата, Регистратор, , ) КАК ЗаказыПокупателейОстаткиИОбороты

В первом случае запрос вернул один документ, а во втором — 41 запись. Выясним, почему это происходит, и рассмотрим правильные варианты реализации выборки.

Причины расхождения данных между документом и регистром

Разберем фундаментальные различия в структуре хранения данных, которые приводят к разнице в результатах выборки:

  1. Детализация движений по строкам табличной части. В регистр накопления при проведении документа записывается отдельная строка для каждой позиции номенклатуры. Если в заказе покупателя указано 10 товаров, документ сформирует 10 записей в регистре.
  2. Разные типы документов-регистраторов. Измерение ЗаказПокупателя в регистре может заполняться не только самим заказом, но и закрывающими или корректирующими документами (например, РеализацияТоваровУслуг, КорректировкаЗаказаПокупателя, ЗакрытиеЗаказовПокупателей). Если за выбранный период были отгрузки по старым заказам, они также попадут в движения.
  3. Специфика таблицы «ОстаткиИОбороты». Виртуальная таблица рассчитывает остатки на начало и конец периода. Заказ может попасть в результат выборки, даже если в указанном диапазоне дат движений по нему не было вовсе, но на начало интервала числился незакрытый остаток.
  4. Проведенные и непроведенные документы. Таблица Документ.ЗаказПокупателя содержит абсолютно все документы (в том числе помеченные на удаление и непроведенные), тогда как в регистр накопления попадают только проведенные документы, сформировавшие движения.
  5. Лишнее обращение через точку к реквизиту «Ссылка». Обращение вида ЗаказПокупателя.Ссылка к полю, которое уже является ссылкой, заставляет платформу выполнять избыточное неявное левое соединение (LEFT JOIN) с таблицей документа, что снижает производительность.

Решение 1. Выборка через виртуальную таблицу «Обороты» с фильтрацией регистратора

Если требуется получить список заказов покупателей, которые сами были оформлены и проведены в указанном периоде (то есть являются регистратором движения типа «Приход»), используем виртуальную таблицу Обороты с фильтрацией по типу регистратора и обязательным ключевым словом РАЗЛИЧНЫЕ:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    ЗаказыПокупателейОбороты.ЗаказПокупателя КАК ЗаказПокупателя
ИЗ
    РегистрНакопления.ЗаказыПокупателей.Обороты(
        &НачДата,
        &КонДата,
        Регистратор,
        Регистратор ССЫЛКА Документ.ЗаказПокупателя
    ) КАК ЗаказыПокупателейОбороты

Обратим внимание на следующие ключевые моменты этой конструкции:

  1. Параметр отбора виртуальной таблицы: условие Регистратор ССЫЛКА Документ.ЗаказПокупателя передается в четвертый параметр виртуальной таблицы, а не в блок ГДЕ. Это позволяет СУБД отсечь ненужные движения до этапа расчета агрегатов.
  2. Ключевое слово РАЗЛИЧНЫЕ: исключает повторение одного и того же заказа, если он содержал несколько строк в табличной части.
  3. Отсутствие .Ссылка: измерение ЗаказПокупателя само по себе хранит ссылку на документ, поэтому повторное разыменование через точку не требуется.

Решение 2. Быстрая выборка из реальной физической таблицы движений

Когда перед нами стоит задача просто получить список заказов-регистраторов без анализа числовых показателей (сумм и количества), использовать виртуальные таблицы Обороты или ОстаткиИОбороты неоптимально. Построение виртуальной таблицы создает лишнюю вычислительную нагрузку на сервер баз данных.

В этом случае гораздо эффективнее обратиться напрямую к физической таблице движений регистра:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    Движения.Регистратор КАК ЗаказПокупателя
ИЗ
    РегистрНакопления.ЗаказыПокупателей КАК Движения
ГДЕ
    Движения.Период МЕЖДУ &НачДата И &КонДата
    И Движения.Регистратор ССЫЛКА Документ.ЗаказПокупателя

Рассмотрим, почему этот способ предпочтительнее для простых списков:

  1. Запрос читает данные напрямую из таблицы движений, где поле Период входит в кластерный индекс.
  2. Платформа не тратит ресурсы на соединение таблиц итогов и расчет оборотов.
  3. Условие ССЫЛКА Документ.ЗаказПокупателя гарантирует, что в выборку попадут только первичные заказы, исключая документы отгрузки и закрытия.

Важные замечания по установке параметров периода

При передаче интервала дат в запрос необходимо учитывать время. Если параметр &КонДата передается без указания времени (например, '2023-10-31 00:00:00'), документы, проведенные в течение дня 31 октября, не попадут в выборку.

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


Запрос.УстановитьПараметр("НачДата", НачалоДня(НачДата));
Запрос.УстановитьПараметр("КонДата", КонецДня(КонДата));

Таким образом, для получения точного списка заказов покупателей из регистра накопления следует отсекать дубли строк с помощью РАЗЛИЧНЫЕ, фильтровать тип регистратора и корректно передавать границы периода во встроенный язык запросов.

← На главную