Use la función incorporada que a menudo se pasa por alto width_bucket()
en combinación con su agregación:
Si sus coordenadas van desde, digamos, 0 a 2000 y desea consolidar todo dentro de cuadrados de 5 a puntos individuales, diseñaría una cuadrícula de 10 (5*2) como esta:
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;
Para minimizar el error podrías GROUP BY
la cuadrícula como se muestra, pero guarde las coordenadas promedio reales:
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 demostrando ambos al lado.
Bueno, este caso en particular podría ser más simple:
...
GROUP BY
device_id
, (pos_x / 10) * 10 -- truncates last digit of an integer
, (pos_y / 10) * 10
...
Pero eso es solo porque el tamaño de la cuadrícula de demostración de 10
coincide convenientemente con el sistema decimal. Intente lo mismo con un tamaño de cuadrícula de 17
o algo...
Expandir a marcas de tiempo
Puede expandir este enfoque para cubrir date
y timestamp
valores convirtiéndolos a la época de Unix (número de segundos desde '1970-1-1') con extract().
SELECT extract(epoch FROM '2012-10-01 21:06:38+02'::timestamptz);
Cuando haya terminado, vuelva a convertir el resultado a timestamp with time zone
:
SELECT timestamptz 'epoch' + 1349118398 * interval '1s';
O simplemente to_timestamp()
:
SELECT to_timestamp(1349118398);