В практических задачах аналитики и учета часто требуется отобрать только тех контрагентов или партнеров, которые совершили свою самую первую покупку в выбранном расчетном периоде (например, в текущем месяце). Если по клиенту уже были оформлены документы реализации ранее (в прошлые месяцы или годы), такие документы и клиенты не должны попадать в выборку.
Разберем различные подходы к построению такого запроса в платформе 1С:Предприятие, проанализируем их плюсы, минусы и особенности производительности.
Рассмотрим самый компактный способ выборки. Если нам требуется получить список контрагентов, чья первая отгрузка произошла строго в заданном интервале дат, мы можем сгруппировать таблицу документов по клиенту и наложить условие на минимальную дату документа.
Посмотрим на пример текста запроса:
ВЫБРАТЬ
РТУ.Контрагент КАК Контрагент
ИЗ
Документ.РеализацияТоваровУслуг КАК РТУ
ГДЕ
РТУ.Проведен = ИСТИНА
СГРУППИРОВАТЬ ПО
РТУ.Контрагент
ИМЕЮЩИЕ
МИНИМУМ(РТУ.Дата) МЕЖДУ &ДатаНачала И &ДатаОкончания
Разберем особенности этого метода:
МИНИМУМ(РТУ.Дата) МЕЖДУ &ДатаНачала И &ДатаОкончания гарантирует, что самый ранний проведенный документ клиента попадает именно в выбранный интервал. Если у контрагента был документ до даты &ДатаНачала, минимум будет меньше, и строка будет отсечена.&ДатаОкончания, он также не попадет в выборку.Контрагент нет соответствующего покрывающего индекса в СУБД. В больших базах данных это может выполняться медленно.Проанализируем классический двухэтапный алгоритм через временные таблицы. Этот способ удобен, когда на выходе требуется получить не просто контрагентов, а сами строки документов отгрузки за период.
Разберем реализацию по шагам:
ВТ_ДокументыПериода все реализации за интересующий интервал.ВТ_КонтрагентыРанее список контрагентов, у которых были движения строго до даты начала периода.ЕСТЬNULL(..., NULL) IS NULL).Посмотрим на пример текста запроса:
ВЫБРАТЬ РАЗЛИЧНЫЕ
РТУ.Ссылка КАК Документ,
РТУ.Контрагент КАК Контрагент
ПОМЕСТИТЬ ВТ_ДокументыПериода
ИЗ
Документ.РеализацияТоваровУслуг КАК РТУ
ГДЕ
РТУ.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
И РТУ.Проведен = ИСТИНА
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
РТУ.Контрагент КАК Контрагент
ПОМЕСТИТЬ ВТ_КонтрагентыРанее
ИЗ
Документ.РеализацияТоваровУслуг КАК РТУ
ГДЕ
РТУ.Дата < &ДатаНачала
И РТУ.Проведен = ИСТИНА
И РТУ.Контрагент В
(ВЫБРАТЬ
ВТ_ДокументыПериода.Контрагент
ИЗ
ВТ_ДокументыПериода)
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ДокПериода.Контрагент КАК Контрагент,
ДокПериода.Документ КАК Документ
ИЗ
ВТ_ДокументыПериода КАК ДокПериода
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_КонтрагентыРанее КАК КонтрагентыРанее
ПО ДокПериода.Контрагент = КонтрагентыРанее.Контрагент
ГДЕ
КонтрагентыРанее.Контрагент ЕСТЬ NULL
Обратим внимание на условие во второй временной таблице: РТУ.Контрагент В (ВЫБРАТЬ ВТ_ДокументыПериода.Контрагент...). Это ограничивает выборку исторических данных только теми клиентами, которые фактически покупали что-то в текущем периоде, что существенно снижает нагрузку на СУБД.
В типовых конфигурациях линейки 1С:Управление торговлей 11, 1С:Комплексная автоматизация 2 и 1С:ERP обращение напрямую к документам не всегда оптимально, так как продажи могут фиксироваться разными документами (РеализацияТоваровУслуг, АктВыполненныхРабот, ОтчетОРозничныхПродажах). Кроме того, учет ведется в разрезе партнеров.
Для ускорения расчетов эффективнее использовать виртуальную таблицу регистра ВыручкаИСебестоимостьПродаж.Обороты. Платформа рассчитывает итоги регистров быстрее, чем сканирует физические таблицы документов.
Посмотрим на пример запроса для прикладных конфигураций:
ВЫБРАТЬ РАЗЛИЧНЫЕ
ВыручкаОбороты.АналитикаУчетаПоПартнерам.Партнер КАК Партнер
ПОМЕСТИТЬ ВТ_БылиПродажиРанее
ИЗ
РегистрНакопления.ВыручкаИСебестоимостьПродаж.Обороты(, &ГраницаНачала, , ) КАК ВыручкаОбороты
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВыручкаПериод.Регистратор КАК Документ,
ВыручкаПериод.АналитикаУчетаПоПартнерам.Партнер КАК Партнер
ИЗ
РегистрНакопления.ВыручкаИСебестоимостьПродаж.Обороты(&ДатаНачала, &ДатаОкончания, Регистратор, ) КАК ВыручкаПериод
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_БылиПродажиРанее КАК ПродажиРанее
ПО ВыручкаПериод.АналитикаУчетаПоПартнерам.Партнер = ПродажиРанее.Партнер
ГДЕ
ПродажиРанее.Партнер ЕСТЬ NULL
При построении запросов на проверку первых документов обязательно учитываем следующие моменты:
ГДЕ Документ.Проведен = ИСТИНА, иначе непроведенные или помеченные на удаление черновики могут ошибочно исключить нового клиента из отчета.&ГраницаНачала рекомендуется передавать объект Новый Граница(&ДатаНачала, ВидГраницы.Исключая) или дату, уменьшенную на 1 секунду.Контрагенты может посчитать его новым клиентом. В управленческих отчетах отбор надежнее строить по партнерам.