Use a função interna muitas vezes esquecida
width_bucket()
em combinação com sua agregação:Se suas coordenadas vão de, digamos, 0 a 2000 e você deseja consolidar tudo dentro de quadrados de 5 para pontos únicos, eu colocaria uma grade de 10 (5*2) assim:
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 o erro você pode
GROUP BY
a grade conforme demonstrado, mas salve as coordenadas médias reais: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 demonstrando ambos ao lado.
Bem, este caso em particular poderia ser mais simples:
...
GROUP BY
device_id
, (pos_x / 10) * 10 -- truncates last digit of an integer
, (pos_y / 10) * 10
...
Mas isso é apenas porque o tamanho da grade de demonstração de
10
corresponde convenientemente ao sistema decimal. Tente o mesmo com um tamanho de grade de 17
ou alguma coisa ... Expandir para carimbos de data/hora
Você pode expandir essa abordagem para cobrir
date
e timestamp
valores convertendo-os para unix epoch (número de segundos desde '1970-1-1') com extract(). SELECT extract(epoch FROM '2012-10-01 21:06:38+02'::timestamptz);
Quando terminar, converta o resultado de volta para
timestamp with time zone
:SELECT timestamptz 'epoch' + 1349118398 * interval '1s';
Ou simplesmente
to_timestamp()
:SELECT to_timestamp(1349118398);