Потому что это весело: использовала новую PostgreSQL 11 функцию "GROUPS
в оконных функциях" для решения проблемы с привязанными локальными максимумами.
Проблема:
dev key ts val
1 u 100000 50
1 u 130100 30050
1 u 160100 60050 -- really single local maximum
1 u 190200 100
1 u 220200 30100 -- local maximum together with next value
1 u 250200 30100
1 u 300000 300
1 u 500000 100
1 u 550000 1000 -- a (tied) local maximum if only 1 before and 1 after is used, which is wrong
1 u 600000 1000
1 u 650000 2000 -- real local maximum together with 2 next rows
1 u 700000 2000
1 u 720000 2000
1 u 750000 300
Новая функция PostgreSQL 11:
В блоге JOOQ объясняется эта функция
Документация Postgres 11
demo: db <> fiddle
SELECT
dev, key, ts, val
FROM (
SELECT
*,
-- B:
max(val) over (order by sum, val GROUPS BETWEEN 1 PRECEDING AND 1 FOLLOWING) as local_max
FROM (
SELECT -- A
*,
sum(is_diff) over (order by ts)
FROM (
SELECT
*,
CASE WHEN val = lag(val) over (order by ts) THEN 0 ELSE 1 END as is_diff
FROM test t
WHERE key = 'u'
)s
)s
)s
WHERE val = local_max
A: Это всего лишь подготовительная часть.Оконным функциям нужен определенный порядок.Если вы сделаете PARTITION BY val
, стол будет заказан сначала val
.Но в этом примере вы хотели бы удерживать ордер на ts
.И тогда вы хотите, чтобы оконная функция магия для val
.Таким образом, в этой части я вычисляю номер группы для тех же значений в прямых следующих строках, удерживая порядок на ts
.( Может быть, это можно сделать лучше? )
Результат таков:
dev key ts val is_diff sum
1 u 100000 50 1 1
1 u 130100 30050 1 2
1 u 160100 60050 1 3
1 u 190200 100 1 4
1 u 220200 30100 1 5 \ same group
1 u 250200 30100 0 5 /
1 u 300000 300 1 6
1 u 500000 100 1 7
1 u 550000 1000 1 8 \ same group
1 u 600000 1000 0 8 /
1 u 650000 2000 1 9 \
1 u 700000 2000 0 9 | same group
1 u 720000 2000 0 9 /
1 u 750000 300 1 10
B: Это новая функция Postgres 11.Теперь можно проверить значения для групп.В прошлом можно было искать фиксированный номер строки.Но теперь вы можете проверить значение следующей группы.Говоря: Если у вас есть 3 три строки с одинаковым значением, вы можете проверить следующее или предыдущее значение, которое не связано независимо от того, сколько строк вы связываете.Это решило проблему очень круто:
Для примера с двумя значениями 1000
: Теперь мы можем проверить: следующее значение больше текущего?Нет, это то же самое.Так что это та же группа.Итак, давайте посмотрим на следующий ряд.Это 2000
, и это больше.Таким образом, текущая строка не может быть локальным максимумом.
С помощью этого группового окна вы можете получить максимальное значение окруженных групп, которое дает вам локальное значение, даже если есть связанные значения.