当子查询引用外部查询中的列时,我遇到了将视图从PostgreSQL转换为Oracle的问题。
此问题似乎已在此处多次讨论,但我无法使用任何修复程序来处理我的特定查询。
查询的目的是让移动设备获得最后记录的位置,并从它的最近检查点/地理边界获得KM的距离,并且它引用3个单独的表:devices,device_locations和checkpoints。
SELECT
d.id,
dl.latitude AS last_latitude,
dl.longitude AS last_longitude,
(SELECT * /* Get closest 'checkpoint' to the last device position by calculating the Great-circle distance */
FROM (
SELECT
6371 * acos(cos(dl.latitude / (180/acos(-1))) * cos(checkpoints.latitude / (180/acos(-1))) * cos((checkpoints.longitude / (180/acos(-1))) - (dl.longitude / (180/acos(-1)))) + sin(dl.latitude / (180/acos(-1))) * sin(checkpoints.latitude / (180/acos(-1)))) AS distance
FROM checkpoints
ORDER BY distance)
WHERE ROWNUM = 1) AS distance_to_checkpoint
FROM devices d
LEFT JOIN ( /* Get the last position of the device */
SELECT l.id,
l.time,
l.latitude,
l.longitude,
l.accuracy
FROM device_locations l
WHERE l.ROWID IN (SELECT MAX(ROWID) FROM device_locations GROUP BY id)
ORDER BY l.id, l.time DESC) dl
ON dl.id = d.id;
我已经坚持了一段时间,并希望有人能把我放在正确的道路上,谢谢。
答案 0 :(得分:1)
我看到两个问题:
AS distance_to_checkpoint,
device_locations l
,而不是派生表dl
- 示例:l.latitude
应为dl.latitude
答案 1 :(得分:1)
首先:查询没有获得最后的设备位置。它获取的ROWID
每ID
个dl.latitude
的记录可能恰好是最新的条目,但完全没有保证。
然后你很可能有范围问题。不幸的是,名称只有一个级别有效,这是一个恼人的限制。 MIN
等在子查询中可能无效,因为它实际上是子查询中的子查询。无论如何,你想要获得的是最小距离,你可以轻松获得ORDER BY
。
子查询中的ROWNUM
在标准SQL中是多余的。 Oracle对他们的ORDER BY
技术做了例外,但我不会使用它。 (并且如上所述,获得最小值甚至是笨拙的。)无论如何,外连接中的select
d.id as device_id,
dl.latitude as last_latitude,
dl.longitude as last_longitude,
(
select min(6371 *
acos(cos(dl.latitude / (180/acos(-1))) *
cos(cp.latitude / (180/acos(-1))) *
cos((cp.longitude / (180/acos(-1))) - (dl.longitude / (180/acos(-1))))
+
sin(dl.latitude / (180/acos(-1))) *
sin(cp.latitude / (180/acos(-1)))
)
)
from checkpoints cp
) as distance
from devices d
left join
(
select
id as device_id, latitude, longitude, time,
max(time) over (partition by id) as max_time
from device_locations
) dl on dl.device_id = d.id and dl.time = dl.max_time;
是多余的。
这就是我解决问题的方法:
DataRetrieve
答案 2 :(得分:1)
这是我的另一个答案的后续行动。为了获得具有最小距离的checkpoints
记录,您将加入表并再次使用窗口函数来选择最佳记录。 E.g:
select
device_id,
last_latitude,
last_longitude,
checkpoint_latitude,
checkpoint_longitude,
distance
from
(
select
device_id,
last_latitude,
last_longitude,
checkpoint_latitude,
checkpoint_longitude,
distance,
min(distance) over (partition by device_id) as min_distance
from
(
select
d.id as device_id,
dl.latitude as last_latitude,
dl.longitude as last_longitude,
cp.latitude as checkpoint_latitude,
cp.longitude as checkpoint_longitude,
6371 *
acos(cos(dl.latitude / (180/acos(-1))) *
cos(cp.latitude / (180/acos(-1))) *
cos((cp.longitude / (180/acos(-1))) - (dl.longitude / (180/acos(-1))))
+
sin(dl.latitude / (180/acos(-1))) *
sin(cp.latitude / (180/acos(-1)))
) as distance
from devices d
left join
(
select
id as device_id, latitude, longitude, time,
max(time) over (partition by id) as max_time
from device_locations
) dl on dl.device_id = d.id and dl.time = dl.max_time
cross join checkpoints cp
)
)
where (distance = min_distance) or (distance is null and min_distance is null);
从Oracle 12c开始,CROSS APPLY
和OUTER APPLY
可以更轻松地编写此类查询。