Verwenden Sie die oft übersehene integrierte Funktion width_bucket()
in Kombination mit Ihrer Aggregation:
Wenn Ihre Koordinaten beispielsweise von 0 bis 2000 verlaufen und Sie alles innerhalb von 5er-Quadraten zu einzelnen Punkten konsolidieren möchten, würde ich ein 10er-Raster (5*2) wie folgt anlegen:
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;
Um den Fehler zu minimieren Sie könnten GROUP BY
das Gitter wie gezeigt, aber speichern Sie die tatsächlichen Durchschnittskoordinaten:
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 demonstriert beides nebeneinander.
Nun, dieser spezielle Fall könnte einfacher sein:
...
GROUP BY
device_id
, (pos_x / 10) * 10 -- truncates last digit of an integer
, (pos_y / 10) * 10
...
Aber das liegt nur an der Demo-Rastergröße von 10
entspricht bequem dem Dezimalsystem. Versuchen Sie dasselbe mit einer Rastergröße von 17
oder so ...
Auf Zeitstempel erweitern
Sie können diesen Ansatz erweitern, um date
abzudecken und timestamp
Werte durch Konvertieren in die Unix-Epoche (Anzahl der Sekunden seit '1970-1-1') mit extract().
SELECT extract(epoch FROM '2012-10-01 21:06:38+02'::timestamptz);
Wenn Sie fertig sind, wandeln Sie das Ergebnis wieder in timestamp with time zone
um :
SELECT timestamptz 'epoch' + 1349118398 * interval '1s';
Oder einfach to_timestamp()
:
SELECT to_timestamp(1349118398);