我有一个具有以下简化结构的 PostgreSQL 数据库表:
- 设备 ID varchar
- Pos_X (int)
- Pos_Y (int)
基本上,该表包含许多设备的二维航点数据。现在我想设计一个查询来减少输出中的坐标数。它应该聚合附近的坐标(对于某个 x,y 阈值)一个例子:
第 1 行:设备 1;603;1205
第 2 行:设备 1;604;1204
如果阈值为 5,则应聚合这两行,因为方差小于 5。知道如何在 PostgreSQL 或 SQL 中执行此操作吗?
我有一个具有以下简化结构的 PostgreSQL 数据库表:
基本上,该表包含许多设备的二维航点数据。现在我想设计一个查询来减少输出中的坐标数。它应该聚合附近的坐标(对于某个 x,y 阈值)一个例子:
第 1 行:设备 1;603;1205
第 2 行:设备 1;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;
好吧,这种特殊情况可能更简单:
...
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' 以来的秒数)来扩展此方法以覆盖date
和值。timestamp
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);
select [some aggregates] group by (pos_x/5, pos_y/5);
哪里可以有任何数字而不是 5,具体取决于您需要多少聚合/