Пропорциональное распределение в запросе

28.06.18

Разработка - Универсальные функции

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

Скачать исходный код

Наименование Файл Версия Размер
Пропорциональное распределение в запросе:
.erf 5,80Kb
2
.erf 2 5,80Kb 2 Скачать

Основная проблема с которой сталкивается разработчик это остатки от распределения. Остатки возникают из-за округлений и представляют собой разницу между распределяемой и распределенной суммами.

Существуют разные методы решения проблемы. Один из методов - перенос разницы на элемент с самым большим значением. Недостатком такого метода является существенное изменение корректируемого элемента, при некоторых условиях. Например большое количество элементов распределения и маленькая точность округления. Иногда такой способ может привести к аномалиям, вплоть до перехода изначально положительных элементов базы распределения в отрицательные значения.

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

  • более затратен по вычислительным ресурсам
  • в результате распределения может случиться, что на элементы с одинаковыми значениями были распределены разные суммы

Вторая проблема разработчика, это определение распределяемой суммы/сумм в процессе выполнения запроса, отсутствие возможности передать распределяемую сумму/суммы в запрос параметром.

Ниже пример пропорционального распределения в запросе 1С методом выравнивания с определением распределяемых сумм в запросе.

ВЫБРАТЬ
	"Элемент1" КАК Элемент,
	"Группа1" КАК Группа,
	2 КАК Значение
ПОМЕСТИТЬ Элементы

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	"Элемент2",
	"Группа2",
	2

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	"Элемент3",
	"Группа2",
	3

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	"Элемент4",
	"Группа3",
	3

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	"Элемент5",
	"Группа3",
	3

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	"Элемент6",
	"Группа3",
	5

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	"Элемент7",
	"Группа3",
	5
	
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	"Группа1" КАК Группа,
	3 КАК РаспределяемаяСумма
ПОМЕСТИТЬ РаспределяемыеГруппы

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	"Группа2",
	9

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	"Группа3",
	7
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	Элементы.Группа КАК Группа,
	СУММА(Элементы.Значение) КАК Итог
ПОМЕСТИТЬ ИтогиПоГруппам
ИЗ
	Элементы КАК Элементы

СГРУППИРОВАТЬ ПО
	Элементы.Группа
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	Элементы1.Элемент КАК Элемент,
	Элементы1.Группа КАК Группа,
	ВЫРАЗИТЬ(Элементы1.Значение КАК ЧИСЛО(15, 2)) КАК Значение,
	ВЫРАЗИТЬ(ЕСТЬNULL(СУММА(Элементы2.Значение), 0) КАК ЧИСЛО(15, 2)) КАК ЗначениеНакопленное
ПОМЕСТИТЬ ЭлементыСНакоплением
ИЗ
	Элементы КАК Элементы1
		ЛЕВОЕ СОЕДИНЕНИЕ Элементы КАК Элементы2
		ПО Элементы1.Элемент > Элементы2.Элемент
			И Элементы1.Группа = Элементы2.Группа

СГРУППИРОВАТЬ ПО
	Элементы1.Элемент,
	Элементы1.Значение,
	Элементы1.Группа
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	Элементы.Элемент КАК Элемент,
	Элементы.Группа КАК Группа,
	Элементы.Значение КАК Значение,
	РаспределяемыеГруппы.РаспределяемаяСумма КАК РаспределяемаяСумма,
	ВЫБОР
		КОГДА ИтогиПоГруппам.Итог = 0
			ТОГДА 0
		ИНАЧЕ (ВЫРАЗИТЬ(РаспределяемыеГруппы.РаспределяемаяСумма * (Элементы.ЗначениеНакопленное + Элементы.Значение) / ИтогиПоГруппам.Итог КАК ЧИСЛО(15, 2))) - (ВЫРАЗИТЬ(РаспределяемыеГруппы.РаспределяемаяСумма * Элементы.ЗначениеНакопленное / ИтогиПоГруппам.Итог КАК ЧИСЛО(15, 2)))
	КОНЕЦ КАК РаспределеноНаЭлемент
ИЗ
	ЭлементыСНакоплением КАК Элементы
		ЛЕВОЕ СОЕДИНЕНИЕ ИтогиПоГруппам КАК ИтогиПоГруппам
		ПО (Элементы.Группа = ИтогиПоГруппам.Группа)
		ЛЕВОЕ СОЕДИНЕНИЕ РаспределяемыеГруппы КАК РаспределяемыеГруппы
		ПО (Элементы.Группа = РаспределяемыеГруппы.Группа)

 

В приложенном файле отчет с приведенным примером распределения. Проверено на релизе 8.3.10.2753.

распределение пропорциональное распределение запрос округление остаток

См. также

Вставляем картинку из буфера обмена (платформа 1С 8.3.24)

Универсальные функции Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Задача: вставить картинку из буфера обмена на форму средствами платформы 1С.

1 стартмани

18.03.2024    2898    2    John_d    11    

56

GUID в 1С 8.3 - как с ними быть

Универсальные функции Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Пришлось помучиться с GUID-ами немного, решил поделиться опытом, мало ли кому пригодится.

12.02.2024    5071    atdonya    22    

51

Переоткрытие внешних обработок

Универсальные функции Платформа 1С v8.3 Бесплатно (free)

На заключительных этапах, когда идет отладка или доработка интерфейса, необходимо много раз переоткрыть внешний объект. Вот один из способов автоматизации этого.

30.11.2023    4110    ke.92@mail.ru    16    

62

Валидация JSON через XDTO (включая массивы)

WEB-интеграция Универсальные функции Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    9410    YA_418728146    6    

143

Печать непроведенных документов для УТ, КА, ERP. Настройка печати по пользователям, документам и печатным формам

Пакетная печать Печатные формы Адаптация типовых решений Универсальные функции Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Абонемент ($m)

Расширение для программ 1С:Управление торговлей, 1С:Комплексная автоматизация, 1С:ERP, которое позволяет распечатывать печатные формы для непроведенных документов. Можно настроить, каким пользователям, какие конкретные формы документов разрешено печатать без проведения документа.

2 стартмани

22.08.2023    2246    25    progmaster    8    

3

Расширение: Быстрые отборы через буфер [Alt+C] Копировать список, [Alt+V] Вставить список, [Ctrl+C] Копировать из файлов

Инструментарий разработчика Универсальные функции Платформа 1С v8.3 Конфигурации 1cv8 1С:Розница 2 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Зарплата и Управление Персоналом 3.x Абонемент ($m)

Копирует в буфер значения из списков, из ячеек отчетов, таблиц, настроек списков, других отборов и вставляет в выбранную настройку отбора. Работает с Объект не найден. Работает как в одной так и между разными базами 1С. Использует комбинации [Alt+C] Копировать список, [Alt+V] Вставить список. Также для копирования данных используется стандартная [Ctrl+C] (например из открытого xls, mxl, doc и т.п. файла скопировать список наименований)

1 стартмани

13.10.2022    16366    142    sapervodichka    112    

130

Система контроля ведения учета [БСП]

Универсальные функции Механизмы типовых конфигураций БСП (Библиотека стандартных подсистем) Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

В данном материале рассмотрим типовой алгоритм подсистемы контроля учета БСП в конфигурациях на примерах.

18.07.2022    7359    quazare    8    

110
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. RustIG 1595 29.06.18 08:16 Сейчас в теме
(0) у меня по этой задаче целая подсистема механизмов получилась: https://infostart.ru/public/829908/
2. val_bel 29.06.18 10:38 Сейчас в теме
Хотелось бы пояснений к логике запросов. Вот например какая логика в этом фрагменте, что есть ЗначениеНакопленное?

ВЫБРАТЬ
	Элементы1.Элемент КАК Элемент,
	Элементы1.Группа КАК Группа,
	ВЫРАЗИТЬ(Элементы1.Значение КАК ЧИСЛО(15, 2)) КАК Значение,
	ВЫРАЗИТЬ(ЕСТЬNULL(СУММА(Элементы2.Значение), 0) КАК ЧИСЛО(15, 2)) КАК ЗначениеНакопленное
ПОМЕСТИТЬ ЭлементыСНакоплением
ИЗ
	Элементы КАК Элементы1
		ЛЕВОЕ СОЕДИНЕНИЕ Элементы КАК Элементы2
		ПО Элементы1.Элемент > Элементы2.Элемент
			И Элементы1.Группа = Элементы2.Группа

СГРУППИРОВАТЬ ПО
	Элементы1.Элемент,
	Элементы1.Значение,
	Элементы1.Группа
;
Показать
5. romankoav 4 29.06.18 17:16 Сейчас в теме
(2) Валерий, обратите внимание на соединение Элементы1.Элемент > Элементы2.Элемент. Немного не обычно, но результат как будто делается соединение по номерам строк таблицы. Соответственно каждая строка будет иметь итог предыдущих строк.
3. romankoav 4 29.06.18 13:32 Сейчас в теме
Это так должно быть, что суммы распределения отличаются в приведенном запросе от того что на картинке к статье?
4. sommid 29.06.18 14:18 Сейчас в теме
https://www.forum.mista.ru/topic.php?id=616801 - распределение с "размазыванием" округления
пост 91 от Speshuric
romankoav; Stety; +2 Ответить
6. romankoav 4 04.07.18 11:32 Сейчас в теме
(4) Да. фактически эта статья усложненный "на группы" вариант с Мисты
7. vpaoli 26 11.10.18 15:14 Сейчас в теме
К сожалению данный алгоритм не работает корректно при произвольных (взятых из практической задачи) значениях базы распределения.
Например, на такой таблице данных он не работает:

Временная таблица: ВТ_УправленческиеРасходы_Распределяемые (Записей в результате: 2)
УправленческиеРасходы_Распределяемые ОперационныйСегмент
27 504 652,9 Сегмент1
3 781 595,5 Прочие


Временная таблица: Данные (Записей в результате: 12)
Объект ОперационныйСегмент База
МК-00001853Экспорт Сегмент1 3 044 491,7155362
МК-00001854Внутренний рынок Сегмент1 3 149 669,367952
МК-00001854Экспорт Сегмент1 14 775 706,07857
МК-00001855Внутренний рынок Сегмент1 3 163 001,7726148
МК-00001855СНГ Сегмент1 968 615,0756743
МК-00001856Экспорт Сегмент1 1 189 318,7971243
МК-00001857Экспорт Сегмент1 1 160 673,1357024
МК-00001860Экспорт Прочие 779 552,4115997
МК-00001861Экспорт Прочие 2 041 707,0284046
МК-00001870Внутренний рынок Прочие 765 162,6133091
МК-00001871Внутренний рынок Сегмент1 53 176,9540751
МК-000013Внутренний рынок Прочие 195 173,4463082

Временная таблица: Итог (Записей в результате: 2)
СуммаБазы ОперационныйСегмент
27 504 652,8972491 Сегмент1
3 781 595,4996216 Прочие

Временная таблица: ДанныеСНакоплением (Записей в результате: 12)
Объект ОперационныйСегмент База БазаНакопленная
МК-000013Внутренний рынок Прочие 195 173,45
МК-00001853Экспорт Сегмент1 3 044 491,72
МК-00001854Внутренний рынок Сегмент1 3 149 669,37 3 044 491,72
МК-00001854Экспорт Сегмент1 14 775 706,08 6 194 161,08
МК-00001855Внутренний рынок Сегмент1 3 163 001,77 20 969 867,16
МК-00001855СНГ Сегмент1 968 615,08 24 132 868,93
МК-00001856Экспорт Сегмент1 1 189 318,8 25 101 484,01
МК-00001857Экспорт Сегмент1 1 160 673,14 26 290 802,81
МК-00001860Экспорт Прочие 779 552,41 195 173,45
МК-00001861Экспорт Прочие 2 041 707,03 974 725,86
МК-00001870Внутренний рынок Прочие 765 162,61 3 016 432,89
МК-00001871Внутренний рынок Сегмент1 53 176,95 27 451 475,94

Временная таблица: ВТ_РаспределеноПоБазе (Записей в результате: 12)
Объект База ОперационныйСегмент РаспределеноПоБазе
МК-000013Внутренний рынок 195 173,45 Прочие 195 173,45
МК-00001853Экспорт 3 044 491,72 Сегмент1 3 044 491,72
МК-00001854Внутренний рынок 3 149 669,37 Сегмент1 3 149 669,37
МК-00001854Экспорт 14 775 706,08 Сегмент1 14 775 706,08
МК-00001855Внутренний рынок 3 163 001,77 Сегмент1 3 163 001,77
МК-00001855СНГ 968 615,08 Сегмент1 968 615,08
МК-00001856Экспорт 1 189 318,8 Сегмент1 1 189 318,8
МК-00001857Экспорт 1 160 673,14 Сегмент1 1 160 673,14
МК-00001860Экспорт 779 552,41 Прочие 779 552,41
МК-00001861Экспорт 2 041 707,03 Прочие 2 041 707,03
МК-00001870Внутренний рынок 765 162,61 Прочие 765 162,61
МК-00001871Внутренний рынок 53 176,95 Сегмент1 53 176,95

Использовался полностью аналогичный код:

ВЫБРАТЬ
    СУММА(Данные.База) КАК СуммаБазы ,
    Данные.ОперационныйСегмент
ПОМЕСТИТЬ Итог
ИЗ
    Данные КАК Данные
СГРУППИРОВАТЬ ПО Данные.ОперационныйСегмент

;
///////////////////////////////////////////////////

ВЫБРАТЬ
    Данные1.Объект КАК Объект,
    Данные1.ОперационныйСегмент  КАК ОперационныйСегмент,
    ВЫРАЗИТЬ(Данные1.База КАК ЧИСЛО(15, 2)) КАК База,
    ВЫРАЗИТЬ(ЕСТЬNULL(СУММА(Данные2.База), 0) КАК ЧИСЛО(15, 2)) КАК БазаНакопленная
ПОМЕСТИТЬ ДанныеСНакоплением
ИЗ
    Данные КАК Данные1
        ЛЕВОЕ СОЕДИНЕНИЕ Данные КАК Данные2
        ПО Данные1.Объект > Данные2.Объект
        	И Данные1.ОперационныйСегмент = Данные2.ОперационныйСегмент

СГРУППИРОВАТЬ ПО
    Данные1.Объект,
    Данные1.База  ,
    Данные1.ОперационныйСегмент
;
////////////////////////////////////////////////////////////­////////////////////


ВЫБРАТЬ
   Данные.Объект, 
    Данные.База,
    Данные.ОперационныйСегмент,
    (ВЫРАЗИТЬ(ВТ_УправленческиеРасходы_Распределяемые.УправленческиеРасходы_Распределяемые * (Данные.БазаНакопленная + Данные.База) / Итог.СуммаБазы КАК ЧИСЛО(15, 2))) 
    - (ВЫРАЗИТЬ(ВТ_УправленческиеРасходы_Распределяемые.УправленческиеРасходы_Распределяемые * Данные.БазаНакопленная / Итог.СуммаБазы КАК ЧИСЛО(15, 2))) КАК РаспределеноПоБазе
ПОМЕСТИТЬ ВТ_РаспределеноПоБазе
ИЗ
    ДанныеСНакоплением КАК Данные 
    ЛЕВОЕ СОЕДИНЕНИЕ Итог КАК Итог
    ПО Итог.ОперационныйСегмент = Данные.ОперационныйСегмент
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_УправленческиеРасходы_Распределяемые КАК ВТ_УправленческиеРасходы_Распределяемые
    ПО ВТ_УправленческиеРасходы_Распределяемые.ОперационныйСегмент =  Итог.ОперационныйСегмент
 
Показать

Но если сначала округлить значения таблицы Данные до 15,2 , то алгоритм начинает работать.
8. starik-2005 3036 18.12.20 16:49 Сейчас в теме
Я так понимаю, что всякий уважающий себя 1С-него просто обязан написать про это свою статью )))
Оставьте свое сообщение