PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Aggregazione di nuvole di punti di coordinate (x,y) in PostgreSQL

Usa la funzione integrata spesso trascurata width_bucket() in combinazione con la tua aggregazione:

Se le tue coordinate vanno, diciamo, da 0 a 2000 e vuoi consolidare tutto all'interno di quadrati di 5 in punti singoli, disegnerei una griglia di 10 (5*2) in questo modo:

SELECT device_id
     , width_bucket(pos_x, 0, 2000, 2000/10) * 10 AS pos_x
     , width_bucket(pos_y, 0, 2000, 2000/10) * 10 AS pos_y
     , count(*) AS ct -- or any other aggregate
FROM   tbl
GROUP  BY 1,2,3
ORDER  BY 1,2,3;

Per ridurre al minimo l'errore potresti GROUP BY la griglia come mostrato, ma salva le coordinate medie effettive:

SELECT device_id
     , avg(pos_x)::int AS pos_x   -- save actual averages to minimize error
     , avg(pos_y)::int AS pos_y   -- cast if you need to
     , count(*)        AS ct      -- or any other aggregate
FROM   tbl
GROUP  BY
       device_id
     , width_bucket(pos_x, 0, 2000, 2000/10) * 10  -- aggregate by grid
     , width_bucket(pos_y, 0, 2000, 2000/10) * 10
ORDER  BY 1,2,3;

sqlfiddle che mostra entrambi insieme.

Bene, questo caso particolare potrebbe essere più semplice:

...
GROUP  BY
       device_id
     , (pos_x / 10) * 10          -- truncates last digit of an integer
     , (pos_y / 10) * 10
...

Ma è solo perché la dimensione della griglia demo di 10 corrisponde convenientemente al sistema decimale. Prova lo stesso con una dimensione della griglia di 17 o qualcosa del genere...

Espandi a timestamp

Puoi espandere questo approccio per coprire date e timestamp valori convertendoli in epoch unix (numero di secondi da '1970-1-1') con extract().

SELECT extract(epoch FROM '2012-10-01 21:06:38+02'::timestamptz);

Quando hai finito, riconvertisci il risultato in timestamp with time zone :

SELECT timestamptz 'epoch' + 1349118398 * interval '1s';

O semplicemente to_timestamp() :

SELECT to_timestamp(1349118398);