running — итог, который переносится по колонке
Когда нужен: значение не разыгрывается, а накапливается: остаток на счёте после каждой операции, счётчик, который только растёт, самая большая нагрузка за всё время. Значение сороковой строки зависит от строк с первой по тридцать девятую.
Все остальные генераторы отвечают на строку по её номеру. Этот не может — и это не ограничение, которое надо обходить, а ровно то, что слово «нарастающий» и значит.
<tdc>
<env count="8" seed="ledger" local="en">
<sequence name="Op"><gen type="number" value="-400..500"/></sequence>
<sequence name="Balance"><gen type="running" of="Op" accumulate="sum" base="1000"/></sequence>
</env>
<block>
<line><data>${{Op}} ${{Balance}}</data></line>
</block>
</tdc>
399 1399 -246 1153 -270 883 159 1042 24 1066 -400 666 419 1085 80 1165
Значения получены с фиксированным seed, то есть воспроизводимы, но точные строки могут
отличаться между версиями ядра. Смотрите на форму, а не на конкретные символы.
Коротко
| Атрибут | Обязателен | Что делает |
|---|---|---|
of | да | Колонка, которую накапливаем. Должна быть объявлена выше этой последовательности |
accumulate | да | sum, min или max |
base | нет | Начальное значение — входящий остаток, начальный пробег |
reset | нет | Колонка, смена значения которой перезапускает итог |
Нарастающий итог ничего не разыгрывает. Он читает уже существующую колонку, не расходует ни одного случайного числа — и потому добавление такой колонки не сдвигает ни одну другую.
reset= — свой итог на каждую группу
Без reset= итог один на весь файл. С ним колонка делится на отрезки, и каждый
накапливается сам по себе — остаток по счёту, а не остаток по запуску.
<env count="9" seed="acct" local="en">
<sequence name="Account"><gen type="text" value="A,A,A,B,B,C,C,C,C" order="sequential"/></sequence>
<sequence name="Op"><gen type="number" value="10..99" decimals="2"/></sequence>
<sequence name="Balance"><gen type="running" of="Op" accumulate="sum" reset="Account"/></sequence>
</env>
A 49.86 49.86 A 21.54 71.40 A 35.12 106.52 B 80.60 80.60 B 98.09 178.69 C 33.58 33.58 C 23.09 56.67 C 72.74 129.41 C 94.78 224.19
base= — это стартовое значение каждого отрезка, а не прогона: с reset= каждая
группа начинает с него заново, и это как раз то, чего хочет входящий остаток по счёту.
Отрезок кончается там, где значение reset= изменилось по сравнению с прошлой
строкой, — значит, группы должны идти подряд. order="sequential" выше это один способ;
сортировка другой, но сортировкой обычно занимается база,
так что чаще всего колонка и так приходит сгруппированной.
Точные копейки
Арифметика идёт на целых числах, умноженных на самую широкую дробь в колонке, и ни разу
не на плавающей точке. 49.86 + 21.54 это 71.40 — и это одно и то же 71.40 во всех
пяти реализациях, чего плавающая точка не гарантирует.
base= участвует в том же масштабе. Входящий остаток 1000.00 расширяет всю колонку до
двух знаков — именно так, как ожидает тот, кто читает выписку.
Порядок объявления
of= и reset= называют колонку, и обе должны быть объявлены выше нарастающего итога
(TDC240). Причина та же, что у parent: итог
строится из колонки, которая уже существует.
error[TDC240]: of="Op" is not a sequence declared above this one --> ledger.tdc:3:54 | 3 | <sequence name="Balance"><gen type="running" of="Op" accumulate="sum"/></sequence> | ^^ | note: A running total is built from a column that already exists, so the column it reads has to come first.
Нарастающий итог, который не сказал, что и как накапливать, — это TDC239.
На каком движке это считается
Потоковые движки отказываются считать нарастающий итог — прямо называя его — и маршрутизатор отправляет конфигурацию на движок в памяти:
tdcv2: a running total ("Balance") is the accumulation of every row before it, so it cannot be computed one row at a time; the in-memory engine handles it (run without a forced streaming engine)Обычно этого сообщения вы не увидите: движок выбирает маршрутизатор, а отказ всплывает только тогда, когда конфигурация назвала потоковый движок сама — то есть попросила, чтобы ей сказали.
Чего это стоит: нарастающий итог живёт в памяти весь запуск, как любая колонка движка в памяти. Это честная граница этого генератора. Выписка на несколько миллионов строк — нормально; выписка на миллиард строк — не то, что делает TDC, потому что весь смысл потоковых движков в том, что строка считается по своему номеру, а здесь — не считается.
Нарастающий итог нужен, когда строке надо знать о строках ДО неё. Когда ей достаточно
знать о себе самой — итог строки из цены и количества, маржа из двух колонок —
<gen type="formula"> делает это и стримится, так что описанная
выше граница по целой колонке к нему не относится.
Всё остальное по-прежнему течёт потоком. Ограничение действует на конфигурацию, а не
на проект: запуск без нарастающего итога не затронут, а нарастающий итог внутри одной
записи —
accumulate= на списке repeat — не стоит вообще ничего и работает на любом движке.
См. также
accumulate=на спискеrepeat— та же идея внутри одной записи, бесплатно на любом движке- Счётчики —
incrementиdecrement: они двигаются фиксированным шагом и считаются по номеру строки - Временные ряды — кривая с трендом и шумом, тоже по одному номеру строки, и обычно это и есть то, что нужно, когда говорят «значение, которое растёт»