Използвайте често пренебрегваната вградена функция width_bucket()
в комбинация с вашата агрегация:
Ако вашите координати са от, да речем, 0 до 2000 и искате да консолидирате всичко в квадрати от 5 до единични точки, бих изложил мрежа от 10 (5*2) по следния начин:
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;
Засвеждане до минимум на грешката можете да GROUP BY
мрежата, както е показано, но запазете действителните средни координати:
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, демонстриращ и двете заедно.
Е, този конкретен случай може да е по-прост:
...
GROUP BY
device_id
, (pos_x / 10) * 10 -- truncates last digit of an integer
, (pos_y / 10) * 10
...
Но това е само защото размерът на демонстрационната мрежа е 10
удобно съвпада с десетичната система. Опитайте същото с размер на мрежата 17
или нещо...
Разгъване до времеви печати
Можете да разширите този подход, за да обхване date
и timestamp
стойности, като ги преобразувате в unix епоха (брой секунди от '1970-1-1') с екстракт ().
SELECT extract(epoch FROM '2012-10-01 21:06:38+02'::timestamptz);
Когато сте готови, преобразувайте резултата обратно в timestamp with time zone
:
SELECT timestamptz 'epoch' + 1349118398 * interval '1s';
Или просто to_timestamp()
:
SELECT to_timestamp(1349118398);