【数据库】查找距离最近的电影院 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):实现复杂查询逻辑

相关推荐
m0_7369191014 分钟前
超越Python:下一步该学什么编程语言?
jvm·数据库·python
m0_7482299925 分钟前
ThinkPHP快速入门:从零到实战
c语言·开发语言·数据库·学习
乐迪信息27 分钟前
乐迪信息:AI防爆摄像机在船舶监控的应用
大数据·网络·人工智能·算法·无人机
阿蒙Amon35 分钟前
C#每日面试题-Thread.Sleep和Task.Delay的区别
java·数据库·c#
Hernon35 分钟前
AI智能体 - 探索与发现 Clawdbot >> Moltbot
大数据·人工智能·ai智能体·ai开发框架
沉舟侧畔千帆过_1 小时前
一个DBA的真心话:搞定Oracle+PG双库,我就靠这招
数据库·oracle·dba
醉风塘1 小时前
【终极解决方案】Oracle ORA-01795错误:IN列表1000条限制的全面突破指南
数据库·oracle
信创天地1 小时前
从 Oracle 到国产数据库:迁移后成本直降 60%、性能反超 30% 的实战秘籍
数据库·oracle
Mikhail_G1 小时前
Mysql数据库操作指南——排序(零基础篇十)
大数据·数据库·sql·mysql·数据分析
沉舟侧畔千帆过_1 小时前
能源核心系统国产化攻坚:智能电网调度系统从 Oracle 到金仓 KES 迁移实录
数据库·oracle·能源·kingbase·金仓数据库