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);