Użyj często pomijanej wbudowanej funkcji width_bucket()
w połączeniu z Twoją agregacją:
Jeśli twoje współrzędne biegną od, powiedzmy, 0 do 2000 i chcesz skonsolidować wszystko w kwadratach od 5 do pojedynczych punktów, ułożyłbym siatkę 10 (5*2) w następujący sposób:
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;
Aby zminimalizować błąd możesz GROUP BY
siatka, jak pokazano, ale zapisz rzeczywiste średnie współrzędne:
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 oba obok.
Cóż, ten konkretny przypadek może być prostszy:
...
GROUP BY
device_id
, (pos_x / 10) * 10 -- truncates last digit of an integer
, (pos_y / 10) * 10
...
Ale to tylko dlatego, że rozmiar siatki demonstracyjnej to 10
wygodnie pasuje do systemu dziesiętnego. Spróbuj to samo z rozmiarem siatki 17
czy coś ...
Rozwiń do znaczników czasu
Możesz rozszerzyć to podejście, aby objąć date
i timestamp
wartości, konwertując je na epokę unixową (liczba sekund od '1970-1-1') za pomocą funkcji extract().
SELECT extract(epoch FROM '2012-10-01 21:06:38+02'::timestamptz);
Kiedy skończysz, przekonwertuj wynik z powrotem na timestamp with time zone
:
SELECT timestamptz 'epoch' + 1349118398 * interval '1s';
Lub po prostu to_timestamp()
:
SELECT to_timestamp(1349118398);