Оригинал на GitHub
Вопрос
Подскажите, пожалуйста, как сделать правильную нумерацию строк в поле #number
в зависимости от даты в поле #date
.
Пример
Есть таблица в ней есть строки, состоящие из двух столбцов date
и number
:
01.03.24 1 07.03.24 2 20.03.24 3
Как сделать, чтобы значения в столбце Порядковый номер пересчитывались в соответствии с датами, где самой ранней дате бы присваивался наименьший порядковый номер, а самой поздней наибольший?
Продолжаю пример, чтобы лучше объяснить вопрос
Добавляю в эту же таблицу строку со значением в поле дата 10.03.24, должно получиться так:
01.03.24 1 07.03.24 2 10.03.24 3 20.03.24 4
И еще нюанс, если добавляю строку с датой уже имеющейся в таблице, например 07.03.24, должно получиться так (номера в таблице должны изменится в соответсвии с новым порядком):
01.03.24 1 07.03.24 2 07.03.24 3 10.03.24 4 20.03.24 5
Как такое реализовать?
Ответ
Задачи со сложной сортировкой в таблицах, например когда нам нужна сквозная сортировка по полю date плюс id, решается через дополнительное техническое поле тип Строка, в котором мы собираем строку Y-m-d-id
и которое можно поставить как поле сортировки по умолчанию для таблицы.
id при этом необходимо добавлять с ведущими нулями, так как сравнение будет вестись в строковом режиме: 10
надо использовать как 00010
.
Количество ведущих нулей определяется по максимальному возможному id в таблице.
Код в техническом поле, создающем сквозной идентификатор сортировки (поле с name teh_order_field
):
=: str`#date + "-" + $zero_prefix + #id`
zero_prefix: strRepeat(str: 0; num: $id_length)
id_length: 10 - strLength(str: #id)
Теперь нам нужно вычислить номер в поле number. Номер вычсляется как number в предыдущей строке по сортировке по полю teh_order_field плюс 1.
Код в поле number:
=: $prev_num + 1
prev_num: select(table: $#ntn; field: $#nf; where: 'teh_order_field' < #teh_order_field; order: 'teh_order_field' desc)
Стоит отметить, что этот код будет корректно работать только в простых таблицах и таблицах циклов. В рассчетных таблицах и временных таблицах нужен другой подход, так строки в них виртуальные и не соответсвуют строкам в базе данных.
Далее необходимо добавить код-действия в поле teh_order_field с тригеррами на добавление, изменение и удаление, которых пересчитает строки идущие за измененной строкой:
Код действия в поле teh_order_field:
ad1=: reCalculate(table: $#ntn; where: 'teh_order_field' > $#nfv)
dl1=: reCalculate(table: $#ntn; where: 'teh_order_field' > $#onfv)
ch1=: reCalculate(table: $#ntn; where: 'teh_order_field' > $min)
min: listMin(list: json`[$#nfv,$#onfv]`)
При изменении мы определяем, какой маркер сортировки был меньше (до или после изменения) и от него пересчитываем, так как изменение даты может идти как в меньшую сторону, так и в большую.
Важно включить для таблицы параметр "Поколоночный пересчет". То есть, нужно чтобы колонка с teh_order_field рассчиталась до конца, когда будет вычисляться number.
Также в расчетной таблице не нужны никакие коды действия для этой задачи. Так как она всегда рассчитывается целиком.
Код в поле number:
= : $key[0] + 1
key: listSearch(list: $list; key: "value" = #teh_order_field)
list: selectList(table: $#ntn; field: 'teh_order_field'; order: 'teh_order_field' asc)
Для оптимизации лучше сделать поле в футере колонки teh_order_field
в котором делать selectList
и в listSearch
брать уже через #list_in_column_futer
.
Код в поле f_precalc в футере колонки teh_order_field:
=: selectList(table: $#ntn; field: 'teh_order_field'; order: 'teh_order_field' asc)
Код в поле number:
= : $key[0] + 1
key: listSearch(list: #f_precalc; key: "value" = #teh_order_field)
Когда у нас поле teh_order_field выбрано как Поле сортировки в настройках таблицы оно срабатывает только в момент загрузки таблицы.
Если у нас все строки таблицы передаются в браузер без разбивки на страницы (без pagination), мы можем обновить их порядок сразу через код форматирования таблицы:
Код форматирования таблицы:
f1=: setRowsOrder(ids: $ids)
ids: selectList(table: $#ntn; field: 'id'; order: 'number' asc)