2017-06-21 2 views
0

Étant donné comme « points »: une tableComment grouper des agrégats dans PostgreSQL en fonction de la commande de plusieurs colonnes?

time | session_id | trail_id 
------------------------------ 
    1 |  1  | 1 
    2 |  1  | 1 
    3 |  1  | 3 
    4 |  1  | 3 
    5 |  1  | 3 
    6 |  1  | 1 
    7 |  1  | 1 
    8 |  1  | 1 
    9 |  1  | 1 
    10 |  1  | 1 

Comment ces articles sont regroupés pour que je puisse utiliser une fonction d'agrégation sur « id_session » par rapport à trail_id, lors de la commande par le temps? c'est-à-dire que je veux que les groupements soient séparés lorsque le trail_id change au fil du temps.

Une requête comme:

SELECT count(session_id), session_id, trail_id 
FROM <?> 

céderais:

count | session_id | trail_id 
------------------------------- 
    2 |  1  | 1 
    3 |  1  | 3 
    5 |  1  | 1 

Je crois que cela peut être fait avec une fonction de fenêtre, mais ont échoué jusqu'à présent.

Ce qui suit ne pas tout à fait arriver là où je dois être, comme il regroupe tous les trail_ids quel que soit le temps:

SELECT session_id, trail_id, 
    first_value(time) OVER (PARTITION BY session_id, trail_id ORDER BY time) as v 
FROM points 

De plus, dans mon environnement de production cas, la table « points » sera le résultat de JOINs et se composent de quelques millions de lignes. Ces points auront un type de géométrie PostGIS et seront agrégés avec la fonction ST_MakeLine(). Performance sage, serait-il mieux essayé en PL/pgSQL?

Répondre

3
with points(time , session_id , trail_id) as(
    select 1 ,  1  , 1 union all 
    select 2 ,  1  , 1 union all 
    select 3 ,  1  , 3 union all 
    select 4 ,  1  , 3 union all 
    select 5 ,  1  , 3 union all 
    select 6 ,  1  , 1 union all 
    select 7 ,  1  , 1 union all 
    select 8 ,  1  , 1 union all 
    select 11 ,  1  , 1 union all 
    select 12 ,  1  , 1 
) 

select count(*), session_id, trail_id 
from (
    select time, session_id, trail_id, 
    row_number() over(order by time) - 
    row_number() over(partition by session_id, trail_id order by time) as grp 
    from points 
)t 
group by grp, session_id, trail_id 
order by min(time) 

Eh bien, cela devrait donner suite ce dont vous avez besoin, mais si

table »Points sera le résultat de JOIN et se composent de quelques rangées de millions

alors peut être la performance ne sera pas si souhaitable. Essayez simplement

+0

C'est intelligent! Et ça marche bien. Malheureusement, c'est pour une preuve de concept que je ne serai pas en mesure de tester vraiment pendant quelques semaines, donc je vais devoir voir comment la performance est alors. –