Ограничение того метода в том, что число строк может быть очень большим, но все же не больше, чем некоторое конкретное число. Например, 1 000 000.
Думаю, что если вопрос практический, то умножать вряд ли требуется столько строчек - быстро наступит переполнение порядка.
Второе ограничение метода "Баттерфляй" - необходимость нумерации строк. Это можно сделать классическим нарастанием. А в последних версиях платформы - появившимся методом RowNumber() или как он там конкретно называется.
(10) Ну, я имел ввиду не буквальное воспроизведение запроса, а собственно метод. В нем по сути складываются (а будут умножаться) пары строчек. Пары с одинаковыми старшими чем первый, двоичными разрядами. 1 и 2, 3 и 4, 5 и 6 и т.п.
В общем, нужно соблюсти принцип, а запись запроса адаптировать к задаче.
Наверное, лучше сделаю это сам, чтобы не разводить споры. Чуть позже.
Если устроят ограничения, упомянутые в (9).
+(9) Еще один вариант: Транзитивное замыкание. Сгодится при числе строк в группе до 100-500. Так как вычислительная сложность будет расти квадратично. Представить строки как вершины графа. Связи исходно задать по условию расположения строк рядом по порядку. То есть: 2015-2016, 2016-2017, 2017-2018. Находить длину пути как произведение длин путей дуг. Ну и поскольку результат не зависит от порядка вычислений, он окажется правильным. Но здесь будет избыточность в вычислениях. Чтобы определить произведение 10 * 30 * 200 * 150 будет считаться и 10 * (30 * 200 * 150) и (10 * 30) * (200 * 150) и (10 * 30 * 200) * 150.
Такой метод я уже кому-то предлагал. Считалось что-то типа скидок или вроде того. Сказали, что пригодилось, работает.
+ (12) Чтобы не быть голословным, приведу конкретный запрос:
ВЫБРАТЬ ДАТАВРЕМЯ(2018, 1, 1) КАК Ключ, 2 КАК Сомножитель ПОМЕСТИТЬ Дано
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ДАТАВРЕМЯ(2017, 1, 1), 2
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ДАТАВРЕМЯ(2016, 1, 1), 2
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ДАТАВРЕМЯ(2015, 1, 1), 2
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ДАТАВРЕМЯ(2014, 1, 1), 2
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ДАТАВРЕМЯ(2013, 1, 1), 2
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ДАТАВРЕМЯ(2012, 1, 1), 2
;
// Пролог: нумерация таблицы Дано в порядке возрастания ключа
ВЫБРАТЬ КОЛИЧЕСТВО(Слева.Ключ) КАК Номер, Дано.Ключ, Дано.Сомножитель
ПОМЕСТИТЬ Строй
ИЗ Дано КАК Слева ВНУТРЕННЕЕ СОЕДИНЕНИЕ Дано КАК Дано ПО Слева.Ключ <= Дано.Ключ
СГРУППИРОВАТЬ ПО Дано.Ключ, Дано.Сомножитель
;
// Пролог: формирование дуг и петель для каждой вершины, включая начальную нулевую
ВЫБРАТЬ Дано.Номер - 1 КАК НачалоДуги, Дано.Номер КАК КонецДуги, Дано.Сомножитель
ПОМЕСТИТЬ Раз
ИЗ Строй КАК Дано
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 0, 0, 1
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ Дано.Номер, Дано.Номер, 1
ИЗ Строй КАК Дано
;
// Рефрен: первое соединение дуг дает пути длины до 2 включительно
ВЫБРАТЬ Слева.НачалоДуги, Справа.КонецДуги, МИНИМУМ(Слева.Сомножитель * Справа.Сомножитель) КАК Сомножитель
ПОМЕСТИТЬ Два
ИЗ Раз КАК Слева ВНУТРЕННЕЕ СОЕДИНЕНИЕ Раз КАК Справа ПО Слева.КонецДуги = Справа.НачалоДуги
СГРУППИРОВАТЬ ПО Слева.НачалоДуги, Справа.КонецДуги
;
// Чтобы потом переиспользовать имя временной таблицы:
УНИЧТОЖИТЬ Раз;
// Рефрен: второе соединение дуг дает пути длины до 4 включительно
ВЫБРАТЬ Слева.НачалоДуги, Справа.КонецДуги, МИНИМУМ(Слева.Сомножитель * Справа.Сомножитель) КАК Сомножитель
ПОМЕСТИТЬ Раз
ИЗ Два КАК Слева ВНУТРЕННЕЕ СОЕДИНЕНИЕ Два КАК Справа ПО Слева.КонецДуги = Справа.НачалоДуги
СГРУППИРОВАТЬ ПО Слева.НачалоДуги, Справа.КонецДуги
;
УНИЧТОЖИТЬ Два;
// Рефрен: третье соединение дуг дает пути длины до 8 включительно
ВЫБРАТЬ Слева.НачалоДуги, Справа.КонецДуги, МИНИМУМ(Слева.Сомножитель * Справа.Сомножитель) КАК Сомножитель
ПОМЕСТИТЬ Два
ИЗ Раз КАК Слева ВНУТРЕННЕЕ СОЕДИНЕНИЕ Раз КАК Справа ПО Слева.КонецДуги = Справа.НачалоДуги
СГРУППИРОВАТЬ ПО Слева.НачалоДуги, Справа.КонецДуги
;
УНИЧТОЖИТЬ Раз;
// Рефрен: четвертое соединение дуг дает пути длины до 16 включительно
ВЫБРАТЬ Слева.НачалоДуги, Справа.КонецДуги, МИНИМУМ(Слева.Сомножитель * Справа.Сомножитель) КАК Сомножитель
ПОМЕСТИТЬ Раз
ИЗ Два КАК Слева ВНУТРЕННЕЕ СОЕДИНЕНИЕ Два КАК Справа ПО Слева.КонецДуги = Справа.НачалоДуги
СГРУППИРОВАТЬ ПО Слева.НачалоДуги, Справа.КонецДуги
;
УНИЧТОЖИТЬ Два;
// Рефрен: пятое соединение дуг дает пути длины до 32 включительно
ВЫБРАТЬ Слева.НачалоДуги, Справа.КонецДуги, МИНИМУМ(Слева.Сомножитель * Справа.Сомножитель) КАК Сомножитель
ПОМЕСТИТЬ Два
ИЗ Раз КАК Слева ВНУТРЕННЕЕ СОЕДИНЕНИЕ Раз КАК Справа ПО Слева.КонецДуги = Справа.НачалоДуги
СГРУППИРОВАТЬ ПО Слева.НачалоДуги, Справа.КонецДуги
;
УНИЧТОЖИТЬ Раз;
// Рефрен: шестое соединение дуг дает пути длины до 64 включительно
ВЫБРАТЬ Слева.НачалоДуги, Справа.КонецДуги, МИНИМУМ(Слева.Сомножитель * Справа.Сомножитель) КАК Сомножитель
ПОМЕСТИТЬ Раз
ИЗ Два КАК Слева ВНУТРЕННЕЕ СОЕДИНЕНИЕ Два КАК Справа ПО Слева.КонецДуги = Справа.НачалоДуги
СГРУППИРОВАТЬ ПО Слева.НачалоДуги, Справа.КонецДуги
;
УНИЧТОЖИТЬ Два;
// Эпилог: результат выбирается из дуг, соединяющих нулевую и текущую вершину, в результате транзитивного замыкания
ВЫБРАТЬ
Дано.Ключ,
Раз.Сомножитель КАК Произведение
ИЗ
Строй КАК Дано
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Раз КАК Раз
ПО (Раз.НачалоДуги = 0)
И Дано.Номер = Раз.КонецДуги
УПОРЯДОЧИТЬ ПО
Дано.Ключ
Показать
Запрос специально написан сжато, чтобы иметь лучшую обзорность. Кому так читать неудобно, может скопировать его к себе в консоль и распаковать конструктором. Первый запрос в пакете - формирование таблицы с данными для проверки. Для удобства считаются степени двойки, которые всем известны. Можно подставить любые числа.
В данном варианте записи может обрабатываться до 64 строк в группе. Если строк вдруг больше, нужно будет подобавлять рефренов. Каждый рефрен увеличивает максимальное число строк вдвое. Поэтому десять рефренов дадут 1024 строки. Это близко к пределу данного метода, поскольку тогда в последней таблице Раз будет порядка 500 000 строк.
Если строк больше, то стоит рассмотреть вариант из (9), который работает линейное время (!!!), но там запись сложнее.
Варианты
1. Сделать ваш запрос вложенным и перемножать в итоговом запросе.
2. Вместо объединения использовать вложенность или временную таблицу для каждого подзапроса
3. В СКД использовать вычислыемые поля.
4. В СКД добавить формулу на закладке "Ресурсы"