SQLite实现有效航线筛选、双向去重及经纬度关联查询
实现方案
这个需求完全可以用单条SQL搞定,不需要拆成多个步骤执行。
注:你原有代码里的AirPorts_SM应该是笔误,下面的示例统一用题目给出的原表名AirPorts,如果是你实际环境里的别名/临时表,自行替换就行。
核心逻辑说明
几个需求点的实现思路很直接:
- 过滤起终点不在机场表的无效航线:用内连接关联机场表,匹配不到的航线会直接被过滤掉,比写两层EXISTS子查询更简洁,还能同时拿到经纬度数据
- 双向重复航线去重:对任意两个通航的机场,统一把IATA编码字典序更小的作为起点、更大的作为终点,这样A→B和B→A会被归为同一条航线,再配合去重就能只保留一条
- 关联经纬度:分别关联两次机场表,一次取起点的经纬度,一次取终点的经纬度
- 按要求格式化输出:用字符串拼接把字段拼成你要的
KEY=VALUE格式就行,不同数据库拼接语法略有差异,下面示例用标准SQL的||拼接符,MySQL环境可以替换为CONCAT()函数。
可直接运行的代码
如果需要直接返回你指定格式的字符串,用下面的语句:
SELECT DISTINCT 'ROUTE_FROM=' || LEAST(ar.ROUTE_FROM, ar.ROUTE_TO) || ', LAT_FROM=' || ap_from.LATITUDE || ', LON_FROM=' || ap_from.LONGITUDE || ', ROUTE_TO=' || GREATEST(ar.ROUTE_FROM, ar.ROUTE_TO) || ', LAT_TO=' || ap_to.LATITUDE || ', LON_TO=' || ap_to.LONGITUDE AS route_detail FROM AirRoutes ar -- 关联起点机场数据,自动过滤起点不存在的无效航线 INNER JOIN AirPorts ap_from ON ap_from.IATA_CODE = LEAST(ar.ROUTE_FROM, ar.ROUTE_TO) -- 关联终点机场数据,自动过滤终点不存在的无效航线 INNER JOIN AirPorts ap_to ON ap_to.IATA_CODE = GREATEST(ar.ROUTE_FROM, ar.ROUTE_TO) GROUP BY ap_from.IATA_CODE, ap_to.IATA_CODE;
如果不需要拼接成字符串,要结构化的字段值,把SELECT部分替换成下面的写法即可:
SELECT DISTINCT LEAST(ar.ROUTE_FROM, ar.ROUTE_TO) AS ROUTE_FROM, ap_from.LATITUDE AS LAT_FROM, ap_from.LONGITUDE AS LON_FROM, GREATEST(ar.ROUTE_FROM, ar.ROUTE_TO) AS ROUTE_TO, ap_to.LATITUDE AS LAT_TO, ap_to.LONGITUDE AS LON_TO FROM AirRoutes ar INNER JOIN AirPorts ap_from ON ap_from.IATA_CODE = LEAST(ar.ROUTE_FROM, ar.ROUTE_TO) INNER JOIN AirPorts ap_to ON ap_to.IATA_CODE = GREATEST(ar.ROUTE_FROM, ar.ROUTE_TO) GROUP BY ap_from.IATA_CODE, ap_to.IATA_CODE;
说明:代码里用
LEAST()和GREATEST()做大小值判断,所有主流数据库(SQLite、MySQL、PostgreSQL、SQL Server 2022+)都支持这两个函数;如果是老版本SQL Server,可以用CASE WHEN替换,比如LEAST(a,b)等价于CASE WHEN a < b THEN a ELSE b END。
补充说明
- 双向去重的逻辑不会漏数据:哪怕原表里只有B→A没有A→B的记录,也会被自动调整为字典序更小的A作为起点、B作为终点,不会丢失航线
- 如果不需要保留起终点相同的无效航线(比如A→A),只需要在语句最后加一句
WHERE ar.ROUTE_FROM != ar.ROUTE_TO即可 - 用内连接加GROUP BY的写法比你原来的EXISTS加DISTINCT的写法执行效率更高,不需要两次遍历机场表做子查询判断
内容的提问来源于stack exchange,提问作者Tim Makins
相关产品推荐
相关产品推荐

