Gebruik de vaak over het hoofd gezien ingebouwde functie width_bucket()
in combinatie met uw aggregatie:
Als je coördinaten van bijvoorbeeld 0 tot 2000 lopen en je alles binnen vierkanten van 5 tot enkele punten wilt consolideren, zou ik een raster van 10 (5*2) als volgt opstellen:
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;
Om de fout te minimaliseren je zou kunnen GROUP BY
het raster zoals gedemonstreerd, maar bewaar de werkelijke gemiddelde coördinaten:
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 demonstreert beide naast.
Welnu, dit specifieke geval zou eenvoudiger kunnen zijn:
...
GROUP BY
device_id
, (pos_x / 10) * 10 -- truncates last digit of an integer
, (pos_y / 10) * 10
...
Maar dat is alleen maar omdat de demo-rastergrootte van 10
komt gemakkelijk overeen met het decimale stelsel. Probeer hetzelfde met een rastergrootte van 17
of zoiets ...
Uitvouwen naar tijdstempels
Je kunt deze aanpak uitbreiden om date
te dekken en timestamp
waarden door ze te converteren naar unix epoch (aantal seconden sinds '1970-1-1') met extract().
SELECT extract(epoch FROM '2012-10-01 21:06:38+02'::timestamptz);
Als je klaar bent, converteer je het resultaat terug naar timestamp with time zone
:
SELECT timestamptz 'epoch' + 1349118398 * interval '1s';
Of gewoon to_timestamp()
:
SELECT to_timestamp(1349118398);