这段代码是一个 PL/pgSQL 存储过程片段,用于查找距离最近的电影院。让我逐行详细解释:
完整代码:
sql
-- 5. 驾驶距离最近的电影院
For cinema in select id, geom from poi where name like '%影%' order by id Loop
closestp2 = ST_Location2Node(ST_Y(cinema.geom),
ST_X(cinema.geom));
select sum(cost) into dist
from pgr_dijkstra('select id, source, target, len as cost from road',
closestp1, closestp2, false);
if min_dist = -1 or dist < min_dist then
min_dist = dist;
min_id = cinema.id;
end if;
End Loop;
逐行解释:
第2行:FOR 循环开始
sql
-- 5. 驾驶距离最近的电影院
For cinema in select id, geom from poi where name like '%影%' order by id Loop
详细解析:
-
For cinema in ... Loop:-
PL/pgSQL 的循环结构
-
cinema:循环变量,包含id和geom字段
-
-
查询语句:
sql
select id, geom from poi where name like '%影%' order by id
-
从
poi(兴趣点)表中查询 -
where name like '%影%':筛选名称包含"影"字的 POI(电影院) -
order by id:按 ID 排序(保证结果确定性) -
返回每个电影院的
id和geom(地理位置)
select id, geom from poi where name like '%影%' order by id
-
表结构假设:
sqlpoi(id, name, geom, ...) -- id: POI 的唯一标识 -- name: 名称(如"万达影城") -- geom: 地理位置(通常是 Point 类型的几何图形)
第3-4行:计算最近的节点
sql
closestp2 = ST_Location2Node(ST_Y(cinema.geom),
ST_X(cinema.geom));
功能:将电影院的地理坐标转换为路网中的最近节点
-
ST_X(cinema.geom)和ST_Y(cinema.geom):-
PostGIS 函数,提取几何点的坐标
-
ST_X():提取经度(X 坐标) -
ST_Y():提取纬度(Y 坐标) -
注意:参数的顺序是
(Y, X)即(纬度, 经度)
-
-
ST_Location2Node(Y, X):-
自定义函数(可能是用户定义的)
-
功能:根据经纬度坐标找到路网中最近的节点
-
输入:纬度(Y),经度(X)
-
输出:路网节点 ID
-
-
赋值:
-
closestp2:存储电影院对应的路网节点 ID -
注意:
closestp1应该在循环前已定义(可能是起点位置)
-
第5-7行:计算最短路径距离
sql
select sum(cost) into dist
from pgr_dijkstra('select id, source, target, len as cost from road',
closestp1, closestp2, false);
功能:计算从起点到当前电影院的最短驾驶距离
-
pgr_dijkstra()函数:-
pgRouting 的最短路径算法
-
参数1:SQL 查询定义图结构
sql'select id, source, target, len as cost from road'-
road表结构:(id, source, target, len, ...) -
len as cost:道路长度作为路径代价
-
-
参数2:
closestp1:起点节点 ID(应该在循环前定义) -
参数3:
closestp2:终点节点 ID(当前电影院) -
参数4:
false:无向图(双向通行)
-
-
select sum(cost) into dist:-
计算最短路径的总长度
-
sum(cost):累加路径上所有边的 cost(即道路长度) -
into dist:将结果存储到变量dist中
-
第8-12行:比较并更新最短距离
sql
if min_dist = -1 or dist < min_dist then
min_dist = dist;
min_id = cinema.id;
end if;
逻辑:维护最短距离和对应的电影院
-
条件判断:
sqlif min_dist = -1 or dist < min_dist then-
min_dist = -1:初始情况,第一次比较 -
or dist < min_dist:找到更短的距离 -
只要满足任一条件就更新
-
-
更新变量:
sqlmin_dist = dist; min_id = cinema.id; -
变量初始化(应该在循环前):
sql
min_dist = -1; -- 初始化为 -1 表示"未找到" min_id = NULL; -- 初始电影院 ID
第13行:循环结束
sql
End Loop;
-
结束 FOR 循环
-
循环结束后,
min_id存储的是最近电影院的 ID,min_dist存储对应的距离
完整逻辑流程:
-
初始化 :设置
min_dist = -1,min_id = NULL -
遍历所有电影院:
-
从
poi表查询所有名称包含"影"的 POI -
对每个电影院:
a. 将其地理位置转换为路网节点 (
closestp2)b. 计算从起点 (
closestp1) 到该节点的最短驾驶距离c. 如果这是第一个电影院或距离更短,更新记录
-
-
结果:循环结束后得到最近的电影院 ID 和距离
假设的完整函数:
sql
-- 假设的完整函数
CREATE OR REPLACE FUNCTION find_nearest_cinema(start_lon float, start_lat float)
RETURNS TABLE(cinema_id int, distance float) AS $$
DECLARE
cinema record;
closestp1 int;
closestp2 int;
dist float;
min_dist float := -1;
min_id int;
BEGIN
-- 将起点坐标转换为最近的路网节点
closestp1 = ST_Location2Node(start_lat, start_lon);
-- 遍历所有电影院
FOR cinema IN
SELECT id, geom FROM poi WHERE name LIKE '%影%' ORDER BY id
LOOP
-- 将电影院坐标转换为最近的路网节点
closestp2 = ST_Location2Node(ST_Y(cinema.geom), ST_X(cinema.geom));
-- 计算最短路径距离
SELECT SUM(cost) INTO dist
FROM pgr_dijkstra(
'SELECT id, source, target, len as cost FROM road',
closestp1, closestp2, false
);
-- 更新最短距离记录
IF min_dist = -1 OR dist < min_dist THEN
min_dist = dist;
min_id = cinema.id;
END IF;
END LOOP;
-- 返回结果
RETURN QUERY SELECT min_id, min_dist;
END;
$$ LANGUAGE plpgsql;
应用场景:
这是一个实时路径规划查询:
-
用户提供当前位置(经纬度)
-
系统查找所有电影院
-
计算到每个电影院的驾驶距离(考虑实际道路)
-
返回距离最近的电影院
这种实现结合了:
-
空间查询(PostGIS):处理地理位置
-
图算法(pgRouting):计算最短路径
-
业务逻辑(PL/pgSQL):实现复杂查询逻辑