【数据库】查找距离最近的电影院 pgSQL 存储过程片段

这段代码是一个 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  
详细解析:
  1. For cinema in ... Loop

    • PL/pgSQL 的循环结构

    • cinema:循环变量,包含 idgeom 字段

  2. 查询语句

sql 复制代码
select id, geom from poi where name like '%影%' order by id
  • poi(兴趣点)表中查询

  • where name like '%影%':筛选名称包含"影"字的 POI(电影院)

  • order by id:按 ID 排序(保证结果确定性)

  • 返回每个电影院的 idgeom(地理位置)

复制代码
select id, geom from poi where name like '%影%' order by id
  1. 表结构假设

    sql 复制代码
    poi(id, name, geom, ...)
    -- id: POI 的唯一标识
    -- name: 名称(如"万达影城")
    -- geom: 地理位置(通常是 Point 类型的几何图形)

第3-4行:计算最近的节点

sql 复制代码
closestp2 = ST_Location2Node(ST_Y(cinema.geom),  
    ST_X(cinema.geom));
功能:将电影院的地理坐标转换为路网中的最近节点
  1. ST_X(cinema.geom)ST_Y(cinema.geom)

    • PostGIS 函数,提取几何点的坐标

    • ST_X():提取经度(X 坐标)

    • ST_Y():提取纬度(Y 坐标)

    • 注意:参数的顺序是 (Y, X)(纬度, 经度)

  2. ST_Location2Node(Y, X)

    • 自定义函数(可能是用户定义的)

    • 功能:根据经纬度坐标找到路网中最近的节点

    • 输入:纬度(Y),经度(X)

    • 输出:路网节点 ID

  3. 赋值

    • 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);
功能:计算从起点到当前电影院的最短驾驶距离
  1. 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:无向图(双向通行)

  2. 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;  
逻辑:维护最短距离和对应的电影院
  1. 条件判断

    sql 复制代码
    if min_dist = -1 or dist < min_dist then  
    • min_dist = -1:初始情况,第一次比较

    • or dist < min_dist:找到更短的距离

    • 只要满足任一条件就更新

  2. 更新变量

    sql 复制代码
        min_dist = dist;  
        min_id = cinema.id;  
  3. 变量初始化(应该在循环前):

    sql

    复制代码
    min_dist = -1;  -- 初始化为 -1 表示"未找到"
    min_id = NULL;  -- 初始电影院 ID

第13行:循环结束

sql

复制代码
End Loop;
  • 结束 FOR 循环

  • 循环结束后,min_id 存储的是最近电影院的 ID,min_dist 存储对应的距离

完整逻辑流程:

  1. 初始化 :设置 min_dist = -1min_id = NULL

  2. 遍历所有电影院

    • poi 表查询所有名称包含"影"的 POI

    • 对每个电影院:

      a. 将其地理位置转换为路网节点 (closestp2)

      b. 计算从起点 (closestp1) 到该节点的最短驾驶距离

      c. 如果这是第一个电影院或距离更短,更新记录

  3. 结果:循环结束后得到最近的电影院 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;

应用场景:

这是一个实时路径规划查询

  • 用户提供当前位置(经纬度)

  • 系统查找所有电影院

  • 计算到每个电影院的驾驶距离(考虑实际道路)

  • 返回距离最近的电影院

这种实现结合了:

  1. 空间查询(PostGIS):处理地理位置

  2. 图算法(pgRouting):计算最短路径

  3. 业务逻辑(PL/pgSQL):实现复杂查询逻辑

相关推荐
杰克逊的日记1 天前
规控算法(规划 + 控制算法)
大数据·算法·云计算·it
2501_941807261 天前
在迪拜智能机场场景中构建行李实时调度与高并发航班数据分析平台的工程设计实践经验分享
java·前端·数据库
Ydwlcloud1 天前
2026年1月云服务器优惠活动全解析:聪明选云的新策略
大数据·服务器·人工智能·云计算
AI Echoes1 天前
LangChain 语义文档分割器与其他文档分割器的使用
大数据·人工智能·python·langchain·agent
week_泽1 天前
小程序云数据库查询操作_2
数据库·小程序
一 乐1 天前
餐厅点餐|基于springboot + vue餐厅点餐系统(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·后端
易天ETU1 天前
2026年光模块市场分析与预见
大数据·运维·网络·人工智能·光模块·光通信
Ydwlcloud1 天前
2026年1月华为云国际促销活动期间如何省钱?
大数据·服务器·人工智能·华为云·云计算
小王和八蛋1 天前
TDDL、Amoeba、Cobar、MyCAT 架构比较
数据库