Använd den ofta förbisedda inbyggda funktionen width_bucket()
i kombination med din sammanställning:
Om dina koordinater går från, säg, 0 till 2000 och du vill konsolidera allt inom kvadrater på 5 till enstaka punkter, skulle jag lägga ut ett rutnät på 10 (5*2) så här:
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;
För att minimera felet du kan GROUP BY
rutnätet som visas, men spara faktiska genomsnittliga koordinater:
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 som visar båda vid sidan av.
Tja, just det här fallet kan vara enklare:
...
GROUP BY
device_id
, (pos_x / 10) * 10 -- truncates last digit of an integer
, (pos_y / 10) * 10
...
Men det beror bara på att demo-rutnätsstorleken är 10
matchar bekvämt decimalsystemet. Prova samma sak med en rutstorlek på 17
eller något ...
Utöka till tidsstämplar
Du kan utöka detta tillvägagångssätt till att omfatta date
och timestamp
värden genom att konvertera dem till unix-epok (antal sekunder sedan '1970-1-1') med extract().
SELECT extract(epoch FROM '2012-10-01 21:06:38+02'::timestamptz);
När du är klar, konvertera resultatet tillbaka till timestamp with time zone
:
SELECT timestamptz 'epoch' + 1349118398 * interval '1s';
Eller helt enkelt to_timestamp()
:
SELECT to_timestamp(1349118398);