sql >> Base de Datos >  >> RDS >> PostgreSQL

Agregar nubes de puntos de coordenadas (x, y) en PostgreSQL

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