Brug den ofte oversete indbyggede funktion width_bucket()
i kombination med din sammenlægning:
Hvis dine koordinater løber fra f.eks. 0 til 2000, og du ønsker at konsolidere alt inden for kvadrater på 5 til enkelte punkter, ville jeg opstille et gitter på 10 (5*2) sådan her:
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;
For at minimere fejlen du kan GROUP BY
gitteret som vist, men gem faktiske gennemsnitlige 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 demonstrerer begge ved siden af.
Nå, denne særlige sag kunne være enklere:
...
GROUP BY
device_id
, (pos_x / 10) * 10 -- truncates last digit of an integer
, (pos_y / 10) * 10
...
Men det er bare fordi demo-gitterets størrelse på 10
passer bekvemt til decimalsystemet. Prøv det samme med en gitterstørrelse på 17
eller noget ...
Udvid til tidsstempler
Du kan udvide denne tilgang til at dække date
og timestamp
værdier ved at konvertere dem til unix-epoke (antal sekunder siden '1970-1-1') med extract().
SELECT extract(epoch FROM '2012-10-01 21:06:38+02'::timestamptz);
Når du er færdig, skal du konvertere resultatet tilbage til timestamp with time zone
:
SELECT timestamptz 'epoch' + 1349118398 * interval '1s';
Eller blot to_timestamp()
:
SELECT to_timestamp(1349118398);