hoe*_*etz 3 sql postgresql aggregate
我有一个PostgreSQL数据库表,具有以下简化结构:
基本上,该表包含许多用于设备的二维航路点数据.现在我想设计一个减少输出中坐标数量的查询.它应聚合附近的坐标(对于某个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;
Run Code Online (Sandbox Code Playgroud)
为了最大限度地减少错误,您可以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;
Run Code Online (Sandbox Code Playgroud)
那么,这个特殊情况可能更简单:
...
GROUP BY
device_id
, (pos_x / 10) * 10 -- truncates last digit of an integer
, (pos_y / 10) * 10
...
Run Code Online (Sandbox Code Playgroud)
但这只是因为演示网格大小10方便地匹配十进制系统.尝试相同的网格大小17或东西......
您可以通过使用extract()将它们转换为unix纪元(自1970-1-1'以来的秒数),将此方法扩展为覆盖date和timestamp值.
SELECT extract(epoch FROM '2012-10-01 21:06:38+02'::timestamptz);
Run Code Online (Sandbox Code Playgroud)
完成后,将结果转换回timestamp with time zone:
SELECT timestamptz 'epoch' + 1349118398 * interval '1s';
Run Code Online (Sandbox Code Playgroud)
或者干脆to_timestamp():
SELECT to_timestamp(1349118398);
Run Code Online (Sandbox Code Playgroud)