PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Aggregieren von (x,y)-Koordinatenpunktwolken in PostgreSQL

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