在PostgreSQL中聚合(x,y)坐标点云

我有一个PostgreSQL数据库表,具有以下简化结构:

>设备ID varchar
> Pos_X(int)
> Pos_Y(int)

基本上,该表包含许多用于设备的二维航路点数据.现在我想设计一个减少输出中坐标数量的查询.它应聚合附近的坐标(对于某个x,y阈值)
一个例子:

第1行:DEVICE1; 603; 1205

第2行:DEVICE1; 604; 1204

如果阈值为5,则应该聚合这两行,因为方差小于5.
知道如何在PostgreSQL或SQL中做到这一点吗?

最佳答案
将经常被忽视的内置函数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 demonstrating both alongside.

那么,这个特殊情况可能更简单:

...
GROUP  BY
       device_id
     , (pos_x / 10) * 10          -- truncates last digit of an integer
     , (pos_y / 10) * 10
...

但这只是因为10的演示网格大小方便地匹配十进制系统.尝试相同的网格大小为17或其他…

扩展到时间戳

您可以使用extract()将此方法扩展为包含日期和时间戳值,方法是将它们转换为unix纪元(自1970-1-1’以来的秒数).

SELECT extract(epoch FROM '2012-10-01 21:06:38+02'::timestamptz);

完成后,将结果转换回时区的时间戳:

SELECT timestamptz 'epoch' + 1349118398 * interval '1s';

或者只是to_timestamp()

SELECT to_timestamp(1349118398);

转载注明原文:在PostgreSQL中聚合(x,y)坐标点云 - 代码日志