Длинное вступление...
Жил-был документ типа маршрутный лист. Ну, некоторое количество заявок на "забрать отсюда вот это (список с параметрами типа количества-веса-объёма) и отвезти вот сюда".
И захотели пользователи, чтобы печатался он так: сначала погрузки с их количествами забираемого, потом разгрузки с их итогами чего везти.
Но вот беда, машина-то едет не поочерёдно "тут взял - там положил", а сначала наберёт в одном месте по пяти заявкам, потом в другом ещё по двум, потом три из первых и одну из вторых выгрузит и так далее. А "одно место" - это не какая-то простая штука типа "точка маршрута", а сложная комбинация из N полей. Ну там адрес, да время с-по, да получатель, да ещё чёрти что...
Вот и лень мне стало каждый раз стыковаться по всей этой комбинаторике. Захотелось простого обхода результата, типа табличка пунктов погрузки, табличка пунктов выгрузки, табличка грузов погрузки, табличка грузов выгрузки - и в коде просто цоп по одному полю грузы текущего пункта. А все свёртки - в запросе, там конструктор удобненький.
Мозг вскипел и выпал в осадок, поскольку с арифметикой у меня плохо, но лень всё равно победила.
Итааак... встречайте:
1. Существует таблица А (в данном случае - набор заявок).
Мы её нумеруем через АВТОНОМЕРЗАПИСИ(), обзывая поле, допустим, НЗ. Да, если слать запрос за запросом на один набор, он у нас будет не с 1, но для данной задачи несущественно, один документ (набор заявок) дважды и быстро редко печатают.
2. Далее таблица А порождает таблицу Б - в которой для каждой заявки вытаскиваются все те поля, по которым потом пойдёт группировка пунктов погрузки и выгрузки. В ней мы берём поле НЗ и... делаем из него поле НЗ2 таким образом:
POW(2, ВТ_Заявки.НЗ) КАК НЗ2
(вообще, конечно, ВЫРАЗИТЬ(вотэтовот как ЧИСЛО(сколькотамможноразрядов,0)), но поскольку у меня плохо с арифметикой, посчитайте, пожалуйста, сами, при каком значении упадёт!)
3. А ещё таблица А порождает таблицу В - которая "что везти", из табличной части оных заявок. И там мы ровно так же издеваемся над НЗ (надо было назвать ХЗ, было бы веселее), только называем его НЗ2_Груз. К сожалению, сразу сделать это в таблице А нельзя, потому что 1С не любит, когда с результатом этой функции делают что-то прямо там же, где вызвали.
4. Смотрим на эту пару таблиц, чешем репу, типа а чо тут упростилось-то. Ну циферки, с каждой строчкой Б всё длиннее, а в В по нескольку раз повторяющиеся.
5. Делаем из таблицы Б таблицы... так, пора вводить нормальные имена, а то запутаемся. Из таблицы рейсов с группировочными полями делаем собственно таблицы пунктов погрузки (ВТ_ПунктыПогрузки) и разгрузки (ВТ_ПунктыРазгрузки) - по нужным полям группируем, а поле НЗ2... СУММИРУЕМ. То есть было у нас:
Заявка|ПолеПогрузки1|ПолеПогрузки2|...|ПолеПогрузкиN|ПолеВыгрузки1|ПолеВыгрузки2|...|ПолеВыгрузкиN|НЗ2
...а получилось:
ПолеПогрузки1|ПолеПогрузки2|...|ПолеПогрузкиN|НЗ2
и
ПолеВыгрузки1|ПолеВыгрузки2|...|ПолеВыгрузкиN|НЗ2
- и обе этих временных таблицы в последней колонке содержат сумму степеней двойки, каждая из которых встречается только раз.
6. А теперь самый мозгозаворот.
Вытаскиваем табличку грузов для первой и для второй. Как? Выбираем из пунктов НЗ2, из грузов - нужные поля (по НЗ2 и там какой-то ещё детализирующей фигне типа "что за груз" группируем, веса-количества суммируем)... и соединяем:
ИЗ
ВТ_ГрузыЗаявок КАК ВТ_ГрузыЗаявок
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_ПунктыПогрузки КАК ВТ_ПунктыПогрузки
ПО (ВЫБОР
КОГДА ВТ_ПунктыПогрузки.НЗ2< ВТ_ГрузыЗаявок.НЗ2_Груз
ТОГДА ЛОЖЬ
КОГДА (ВЫРАЗИТЬ(ВТ_ПунктыПогрузки.НЗ2 / ВТ_ГрузыЗаявок.НЗ2_Груз- 0.5 КАК ЧИСЛО(15, 0))) - 2 * (ВЫРАЗИТЬ((ВЫРАЗИТЬ(ВТ_ПунктыПогрузки.НЗ2/ ВТ_ГрузыЗаявок.НЗ2_Груз- 0.5 КАК ЧИСЛО(15, 0))) / 2 - 0.5 КАК ЧИСЛО(15, 0))) = 1
ТОГДА ИСТИНА
ИНАЧЕ ЛОЖЬ
КОНЕЦ)
...а было бы в запросе 1С целочисленное деление и остаток - было бы проще, первое условие бы не понадобилось.
7. Запрос, конечно, пакетом, результаты, конечно, в структуру, и на выходе в процедуре печати выдираем кусочки груза по пунктам по ОДНОМУ ключу:
Для Каждого строПогр из ТаблицаПогрузки Цикл
ТабДокумент.Вывести(облПогрузкаШапка);
ГрузыПункта=ГрузыПогрузки.Скопировать(Новый Структура("НЗ2",строПогр.НЗ2));
Для Каждого строГруза Из ГрузыПункта Цикл
//трампампам заполняются паарметры
ТабДокумент.Вывести(облСтрокаГруз);
КонецЦикла;
ТабДокумент.Вывести(облПодвалГруз);
КонецЦикла;
И для выгрузки аналогично.
Решение не претендует на оптимальность, осмысленность и прочие умные вещи и является исключительно демонстрацией того, что лень - двигатель прогресса (иногда совсем не в ту сторону, куда стоило бы).
Оптимизация приветствуется!
В процессе мозголомания были изучены (и местами даже поняты!):
1. "Запрос-комбинатор" Ильдаровича (Ильдарович велик!)
2. Ловушка функции запроса АВТОНОМЕРЗАПИСИ() Макрушина
3. Ограничения разрядности в запросах (потому что первая версия была десятичная, но упала уже на 30 строках)
4. ГигаЧат (потому что с арифметикой у меня ПЛОХО) - кстати, предложенные им алгоритмы косячили на части наборов данных, поэтому пришлось использовать свой мозг
5. Масса "статей" по "Окр" и "Выразить" - коллеги, будьте бдительны, даже на сайтах франчайзи сейчас часть материалов от ИИ и там ЛЮТАЯ ХРЕНЬ, жаль, не скринила.
...а также синдром-дефицита-вау-Галуа, то есть всё, что добрый гугл подсунул в "не хотите ли почитать".