Použijte často přehlíženou vestavěnou funkci width_bucket()
v kombinaci s vaší agregací:
Pokud vaše souřadnice sahají řekněme od 0 do 2000 a chcete vše sloučit v rámci čtverců po 5 do jednotlivých bodů, rozložil bych mřížku 10 (5*2) takto:
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;
Chcete-li minimalizovat chybu můžete GROUP BY
mřížku, jak je ukázáno, ale uložte skutečné průměrné souřadnice:
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 demonstruje obojí vedle sebe.
Tento konkrétní případ by mohl být jednodušší:
...
GROUP BY
device_id
, (pos_x / 10) * 10 -- truncates last digit of an integer
, (pos_y / 10) * 10
...
Ale to jen proto, že velikost mřížky ukázky je 10
vhodně odpovídá desítkové soustavě. Zkuste totéž s velikostí mřížky 17
nebo tak něco ...
Rozbalit na časová razítka
Tento přístup můžete rozšířit na date
a timestamp
hodnoty jejich převodem na unixovou epochu (počet sekund od '1970-1-1') pomocí extraktu().
SELECT extract(epoch FROM '2012-10-01 21:06:38+02'::timestamptz);
Až budete hotovi, převeďte výsledek zpět na timestamp with time zone
:
SELECT timestamptz 'epoch' + 1349118398 * interval '1s';
Nebo jednoduše to_timestamp()
:
SELECT to_timestamp(1349118398);