При построении отчетов по взаиморасчетам в 1С часто возникает необходимость сопоставить документы отгрузки (реализации) и документы оплаты, если они не связаны напрямую реквизитами сделки или документами-основаниями. Рассмотрим задачу, когда по объекту учета (например, по заказу или контрагенту) есть список реализаций и список оплат, и требуется распределить поступающие платежи по отгрузкам по порядку их возникновения (алгоритм ФИФО) исключительно с помощью запроса.
Проанализируем типовой пример. Пусть у нас есть две таблицы данных:
Наш цель — получить единый результат запроса со следующей структурой распределения:
Для связывания двух последовательностей без прямой ссылки применяется математический подход с перевод сумм в числовые интервалы. Разберем его по шагам:
[ПорядокРаспределенияС, ПорядокРаспределенияПо].Посмотрим на практическую реализацию этого алгоритма в виде пакета запросов:
ВЫБРАТЬ "Р1" КАК Ячейка, 1000 КАК Количество, ДАТАВРЕМЯ(2016, 10, 1) КАК Дата ПОМЕСТИТЬ Реализация
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Р2", 2000, ДАТАВРЕМЯ(2016, 10, 3)
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Р3", 3000, ДАТАВРЕМЯ(2016, 10, 5) ;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ "О1" КАК Товар, 1500 КАК Количество, ДАТАВРЕМЯ(2016, 10, 2) КАК Дата ПОМЕСТИТЬ Оплата
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "О2", 1000, ДАТАВРЕМЯ(2016, 10, 4)
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "О3", 3000, ДАТАВРЕМЯ(2016, 10, 10) ;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Реализация.Ячейка КАК Ячейка,
Реализация.Количество КАК Количество,
ЕСТЬNULL(СУММА(Реализация1.Количество), 0) + 1 КАК ПорядокРаспределенияС,
ЕСТЬNULL(СУММА(Реализация1.Количество), 0) + Реализация.Количество КАК ПорядокРаспределенияПо,
Реализация.Дата
ПОМЕСТИТЬ РеализацияПоПорядку
ИЗ
Реализация КАК Реализация
ЛЕВОЕ СОЕДИНЕНИЕ Реализация КАК Реализация1
ПО Реализация.Ячейка > Реализация1.Ячейка
СГРУППИРОВАТЬ ПО
Реализация.Ячейка,
Реализация.Количество,
Реализация.Дата ;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Оплата.Товар КАК Товар,
Оплата.Количество КАК Количество,
ЕСТЬNULL(СУММА(Оплата1.Количество), 0) + 1 КАК ПорядокРаспределенияС,
ЕСТЬNULL(СУММА(Оплата1.Количество), 0) + Оплата.Количество КАК ПорядокРаспределенияПо,
Оплата.Дата
ПОМЕСТИТЬ ОплатаПоПорядку
ИЗ
Оплата КАК Оплата
ЛЕВОЕ СОЕДИНЕНИЕ Оплата КАК Оплата1
ПО Оплата.Товар > Оплата1.Товар
СГРУППИРОВАТЬ ПО
Оплата.Товар,
Оплата.Количество,
Оплата.Дата ;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
РеализацияПоПорядку.Ячейка КАК Реализация,
ОплатаПоПорядку.Товар КАК Оплата,
ВЫБОР
КОГДА ОплатаПоПорядку.ПорядокРаспределенияПо < РеализацияПоПорядку.ПорядокРаспределенияС
ТОГДА ОплатаПоПорядку.ПорядокРаспределенияС
ИНАЧЕ РеализацияПоПорядку.ПорядокРаспределенияС
КОНЕЦ + 1 КАК Количество,
ОплатаПоПорядку.Дата КАК ДатаОплаты
ИЗ
РеализацияПоПорядку КАК РеализацияПоПорядку
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ОплатаПоПорядку КАК ОплатаПоПорядку
ПО РеализацияПоПорядку.ПорядокРаспределенияС <= ОплатаПоПорядку.ПорядокРаспределенияПо
И РеализацияПоПорядку.ПорядокРаспределенияПо >= ОплатаПоПорядку.ПорядокРаспределенияС
При использовании данного подхода в реальных конфигурациях (например, «Управление торговлей 10.3») нужно учитывать несколько важных аспектов:
Реализация.Ссылка > Реализация1.Ссылка) при большом количестве документов создает значительную нагрузку на СУБД. Для больших объемов данных рекомендуется выполнять распределение программно во временных таблицах значений BSL с помощью циклов.СУММА(...) НАД (...), что существенно ускоряет выполнение запроса.ВзаиморасчетыСКонтрагентами). В этом случае предпочтительнее получать данные из виртуальных таблиц оборотов регистра, не совершая ручных вычислений в запросе.