Fonction de fenêtre PostgreSQL avec LIMIT
-
22-12-2019 - |
Question
La requête ci-dessous regroupe les résultats de first
dans 4 bacs de dates équidistants et regroupe en moyenne the_value
dans chaque bac.
WITH first as(
SELECT
extract(EPOCH FROM foo.t_date) as the_date,
foo_val as the_value
FROM bar
INNER JOIN foo
ON
foo.user_id = bar.x_id
and
foo.user_name = 'xxxx'
)
SELECT bin, round(sum(bin_sum) OVER w /sum(bin_ct) OVER w, 2) AS running_avg
FROM (
SELECT width_bucket(first.the_date
, x.min_epoch, x.max_epoch, x.bins) AS bin
, sum(first.the_value) AS bin_sum
, count(*) AS bin_ct
FROM first
, (SELECT MIN(first.the_date) AS min_epoch
, MAX(first.the_date) AS max_epoch
, 4 AS bins
FROM first
) x
GROUP BY 1
) sub
WINDOW w AS (ORDER BY bin)
ORDER BY 1;
J'aimerais pouvoir calculer uniquement la moyenne des 20 les plus bas. the_value
est dans chaque bac.D'après d'autres articles ici sur Stackoverflow, j'ai vu que c'est possible et que peut-être ORDER BY the_value
et rank()
est la meilleure façon de procéder.Mais mon problème est que je ne sais pas où ma requête actuelle doit être modifiée pour implémenter cela.
Toute idée serait appréciée.
Postgres version 9.3
La solution
Utiliser row_number()
sur chaque bac.
Calculez d’abord le numéro de ligne rn
, puis appliquez WHERE rn < 21
à l'étape suivante :
WITH first AS (
SELECT extract(EPOCH FROM foo.t_date) AS the_date
, foo_val AS the_value
FROM bar
JOIN foo ON foo.user_id = bar.x_id
AND foo.user_name = 'xxxx'
)
, x AS (
SELECT MIN(the_date) AS min_epoch
, MAX(the_date) AS max_epoch
FROM first
)
, y AS (
SELECT width_bucket(f.the_date, x.min_epoch, x.max_epoch, 4) AS bin, *
FROM first f, x
)
, z AS (
SELECT row_number() OVER (PARTITION BY bin ORDER BY the_value) AS rn, *
FROM y
)
SELECT bin, round(sum(bin_sum) OVER w / sum(bin_ct) OVER w, 2) AS running_avg
FROM (
SELECT bin
, sum(the_value) AS bin_sum
, count(*) AS bin_ct
FROM z
WHERE rn < 21 -- max 20 lowest values
GROUP BY 1
) sub
WINDOW w AS (ORDER BY bin)
ORDER BY 1;
CTE y
et z
pourraient être confondus.De la même manière first
et x
pourraient être confondus.
Mais c'est plus clair ainsi.
Non testé, car nous n'avons pas de données de test.