SQL查询获取连接航班的src到dest路径

2024-02-10

我想解决一个问题,我希望找到从 src 到dest 的飞行路径,包括转机航班,如果可能的话,按所需时间对其进行排序。

我可以使用像 listagg 这样的东西以某种方式将中间航班聚合为字符串吗?

我们可以将转机航班的数量和所用的时间限制在一定范围内。

我现在以此为起点,这为我提供了转机航班

with  cap as (select 30 time_cap , 5 connect_cap), 
 connecting as 
    (select f1.src src1
          , f1.dest dest1
          , f1.stt st1
          , f1.endt end1
          , f2.src src2
          , f2.dest dest2
          , f2.stt st2
          , f2.endt end2
          , (f2.endt - f1.stt) as time 
     from flight f1 
     inner join flight f2 on f1.dest = f2.src 
     where f1.endt < f2.stt)

我的桌子现在看起来像这样

\d+ flight
                                  Table "public.flight"
 Column |            Type             | Modifiers | Storage  | Stats target | Description 
--------+-----------------------------+-----------+----------+--------------+-------------
 src    | character varying(20)       |           | extended |              | 
 dest   | character varying(20)       |           | extended |              | 
 stt    | timestamp without time zone |           | plain    |              | 
 endt   | timestamp without time zone |           | plain    |              | 

这是一个已经结束的面试问题。

图 bfs 类型的解决方案可以在 sql 查询中解决吗?

即使是一个不起作用的查询(伪代码 - 如果尝试的话会起作用)或方法也可以。

在下面的查询中, 我想在 string_agg 中找出一种方法,可以检查最后一个目的地是否是我想去的目的地。

with flight as (select f1.src||'-'||f1.dest||','||f2.src||'-'||f2.dest route
                     , f1.src src1
                     , f1.dest dest1
                     , f1.stt st1
                     , f1.endt end1
                     , f2.src src2
                     , f2.dest dest2
                     , f2.stt st2
                     , f2.endt end2
                     , (f2.endt - f1.stt) as time 
                from flight f1 
                inner join flight f2 on f1.dest = f2.src 
                where f1.endt < f2.stt) 

select string_agg(route,',') from flight ;

查询航班的输出

  route  | src1 | dest1 |         st1         |        end1         | src2 | dest2 |         st2         |        end2         |   time   
---------+------+-------+---------------------+---------------------+------+-------+---------------------+---------------------+----------
 a-b,b-c | a    | b     | 2017-05-17 09:31:56 | 2017-05-17 14:31:56 | b    | c     | 2017-05-17 15:31:56 | 2017-05-17 16:31:56 | 07:00:00

SQL 中的这些类型的树遍历问题可以使用特殊语法来解决WITH RECURSIVE https://www.postgresql.org/docs/current/static/queries-with.html.

为了测试该解决方案,让我们使用虚拟数据创建下表:

CREATE TABLE flight (
  src TEXT
, dest TEXT
, stt TIMESTAMP
, endt TIMESTAMP);

INSERT INTO flight VALUES 
('SIN', 'DAC', '2016-12-31 22:45:00', '2017-01-01 01:45:00'),
('DAC', 'SIN', '2017-01-01 16:30:00', '2017-01-01 21:30:00'),
('SIN', 'DAC', '2017-01-01 22:45:00', '2017-01-02 01:45:00'),
('DAC', 'DEL', '2017-01-01 10:00:00', '2017-01-01 11:30:00'),
('DEL', 'DAC', '2017-01-01 12:30:00', '2017-01-01 14:00:00'),
('DAC', 'CCU', '2017-01-01 10:30:00', '2017-01-01 11:15:00'),
('CCU', 'DAC', '2017-01-01 11:45:00', '2017-01-01 12:30:00'),
('SIN', 'DEL', '2017-01-01 11:00:00', '2017-01-01 15:00:00'),
('DEL', 'SIN', '2017-01-01 16:30:00', '2017-01-01 20:30:00'),
('CCU', 'DEL', '2017-01-01 12:00:00', '2017-01-01 12:45:00'),
('DEL', 'CCU', '2017-01-01 13:15:00', '2017-01-01 14:00:00');

递归 CTE 很难理解,所以我将一点一点地构建逻辑。

在递归 CTE 中,有两个部分。锚子查询和递归子查询。首先执行锚子查询,然后执行递归子查询,直到返回空结果集。棘手的部分(至少对我来说)是构造将执行从 1 个节点到下一个节点的遍历的连接。

锚点和递归子查询使用UNION ALL(或者有时UNION)并返回。

由于我们对航班路线感兴趣,因此首先使用一个简单的锚点子查询:

SELECT src, ARRAY[src] path, dest FROM flight

上面的查询有 3 列,分别是开始、路径和结束,在第二列中,我们将src字段来自TEXT to TEXT[]。虽然这不是严格需要的,但它将大大简化其余步骤,因为数组很容易附加。

使用上面的锚查询,我们现在可以定义递归 cte。

WITH RECURSIVE flight_paths (src, path, dest) AS (
SELECT
  src
, ARRAY[src]
, dest 
FROM flight
UNION ALL
SELECT
  fp.src
, fp.path || f.src -- appends another 'flight source'
, f.dest -- updates the dest to the new dest
FROM flight f
JOIN flight_paths fp ON f.src = fp.dest 
-- this is the join that links the tree nodes
WHERE NOT f.src = ANY(fp.path) 
-- this condition prevents infinite recursion by not visiting nodes that have already been visited.
) SELECT * FROM flight_paths
-- finally, we can select from the flight_paths recursive cte

上面返回了 136 行以及我的测试数据。前 15 行如下所示:

src path        dest
SIN {SIN}       DAC
DAC {DAC}       SIN
SIN {SIN}       DAC
DAC {DAC}       DEL
DEL {DEL}       DAC
DAC {DAC}       CCU
CCU {CCU}       DAC
SIN {SIN}       DEL
DEL {DEL}       SIN
CCU {CCU}       DEL
DEL {DEL}       CCU
DEL {DEL,CCU}   DAC
DAC {DAC,CCU}   DAC
DEL {DEL,CCU}   DEL
DAC {DAC,CCU}   DEL
DEL {DEL,CCU}   DEL
DAC {DAC,CCU}   DEL

这部分,树遍历的设置,是编写递归 cte 中最难的部分。现在,遍历已经设置完毕,我们可以修改上面的内容:

  1. 我们从源头开始,到目的地结束
  2. 到达目的地时停止迭代
  3. 仅当到达(A-B)

对于这个例子,让src := SIN & dest := CCU

WITH RECURSIVE flight_paths (src, path, dest, stt, endt) AS (
SELECT
  src
, ARRAY[src]
, dest 
, stt
, endt
FROM flight
UNION ALL
SELECT
  fp.src
, fp.path || f.src
, f.dest 
, fp.stt
, f.endt -- update endt to the new endt
FROM flight f
JOIN flight_paths fp ON f.src = fp.dest 
WHERE NOT f.src = ANY(fp.path) 
  AND NOT 'CCU' = ANY(fp.path) 
  -- (2) this new predicate stop iteration when the destination is reached
  AND f.stt > fp.endt
  -- (3) this new predicate only proceeds the iteration if the connecting flights are valid
) 
SELECT * 
FROM flight_paths
WHERE src = 'SIN' AND dest = 'CCU'
-- (1) specify the start & end

这给出了 2 条可能的路线,其中第一个航班的起飞时间为列stt最后一班航班的到达时间为endt:

src path            dest    stt                 endt
SIN {SIN,DAC}       CCU     2016-12-31 22:45:00 2017-01-01 11:15:00
SIN {SIN,DAC,DEL}   CCU     2016-12-31 22:45:00 2017-01-01 14:00:00

现在可以非常轻松地细化结果集。例如,最终查询可以修改为仅在中午之前到达目的地的返程航班,如下所示:

SELECT * 
FROM flight_paths
WHERE src = 'SIN' AND dest = 'CCU' 
  AND endt::time < '12:00:00'::time

从现在开始,在递归 cte 中添加计算飞行时间和连接时间的列,然后筛选出符合这两个时间谓词的航班也相当容易。我希望我已经为您提供了足够的详细信息来生成这两个变体。

您还可以通过过滤长度来限制连接数path数组,尽管一旦达到最大连接数,停止递归 cte 中的迭代可能会更有效。

最后一点:为了让事情变得简单,我之前使用了不包括最终目的地的路径,例如{SIN, DAC, DEL}而不是航班顺序{SIN-DAC, DAC-DEL, DEL-CCU} (或中途停留{DAC, DEL}),但我们可以很容易地得到这些表示,如下所示:

WITH RECURSIVE flight_paths (src, flights, path, dest, stt, endt) AS (
SELECT
  src
, ARRAY[src || '-' || dest]
, ARRAY[src]
, dest 
, stt
, endt
FROM flight
UNION ALL
SELECT
  fp.src
, fp.flights || (f.src || '-' || f.dest)
, fp.path || f.src
, f.dest
, fp.stt
, f.endt
FROM flight f
JOIN flight_paths fp ON f.src = fp.dest 
WHERE NOT f.src = ANY(fp.path) 
  AND NOT 'CCU' = ANY(fp.path) 
  AND f.stt > fp.endt
) 
SELECT flights, stt, endt, path[2:] stopovers
FROM flight_paths
WHERE src = 'SIN' AND dest = 'CCU'
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SQL查询获取连接航班的src到dest路径 的相关文章

随机推荐

  • 调整窗口矩形文档

    MSDN 库将调整窗口矩形的 dwStyle 参数记录为 需要计算所需尺寸的窗口的窗口样式 请注意 您不能 指定 WS OVERLAPPED 样式 我还没有找到任何解释 他们所说的 不能 是什么意思 为什么我不能这样做 The WS OVE
  • 在 Javascript 中查看多页 TIFF

    我目前有多页TIFF图像 我需要通过 Javascript 逐页浏览它们 我对此一无所知 你能帮助我吗 我发现了一些其他问题 但似乎没有一个与 Javascript 有关 谢谢 我使用 Emscripten 将 LibTIFF 库移植到 J
  • 验证 .htaccess 文件中的 Googlebot

    我已经调查了一下 下面的代码可以工作吗 没那么容易检查 RewriteEngine on HostnameLookups Double RewriteCond REMOTE HOST googlebot com NC RewriteRule
  • 在 python 子进程中使用 exec 查找命令给出错误

    我正在尝试使用子进程模块 python 执行以下命令 usr bin find
  • Firefox 扩展内容脚本不会加载和附加 HTML

    下面的所有内容都可以在 Chrome 扩展中运行 但在移植到 Firefox 时会默默失败 加载中test html除非我删除 from it 附加 test element对身体 Firefox 扩展的样式是否必须放入单独的文件中 为什么
  • 我的 ViewModel 应该有视图或 ViewModel 的 ObservableCollection 吗?

    我试图理解使用时的基本 MVVM 设计方法项目控制通过绑定它数据模板 to 可观察集合在视图模型上 我见过绑定到 ObservableCollections 的示例strings Views and 视图模型 绑定到字符串似乎只是为了dem
  • 如何在 firefox 扩展中创建 JSON post 请求?

    我正在尝试调用 Google API 这是来自 Firefox 扩展的 JSON post 请求 例如 POST https www googleapis com urlshortener v1 url Content Type appli
  • Mac OS 10.9 不显示 Arduino 的 USB 调制解调器

    我正在尝试选择 dev tty usbmodem on my Arduino Lenardo设备 操作系统是Mac OSX 10 9 问题是它没有显示 我什至尝试安装FTDI http www ftdichip com Drivers VC
  • 高效的 p​​yspark join

    我读过很多关于如何在 pyspark 中进行高效连接的文章 我发现实现高效连接的方法基本上有 如果可以的话 使用广播连接 我通常不能因为数据框太大 考虑使用非常大的集群 我宁愿不因为 Use the 相同的分区器 最后一个是我宁愿尝试的一个
  • 双破折号 [--] 选项在 git Reset 上有什么作用?

    我见过这样的命令 git reset e542 readme txt 我了解此命令将提交 e542 中的文件 readme txt 的内容放入索引中 但什么是 选项在那里做什么 git reset 手册页将其列为前两种形式的可选 但我找不到
  • 如何构建神经网络来将两个数字相乘

    我正在尝试构建一个将 2 个数字相乘的神经网络 为了做同样的事情 我借助了 scikit learn 我想要一个具有 2 个隐藏层 5 3 和 ReLU 作为激活函数的神经网络 我已经定义了我的MLPRegressor如下 X data d
  • 校准 UI 加速度计?

    在我的应用程序中 我使用加速度计来控制游戏中的角色 现在我只允许纵向方向 因此用户必须向右或向左倾斜设备才能移动角色 到目前为止效果很好 我现在想要完成的是 校准 加速度计以考虑用户当前正在玩的倾斜度 假设用户侧躺 这些值将会倾斜 因为它没
  • 对于 BLOB,“length() IS NULL”是否与“IS NULL”等效且更快?

    我在 SSD 上有一个约 90 MB 的 SQLite 数据库 主要由消息附件组成 其中包括 BLOB 列内容 用于存储二进制附件数据 现在我发现以下查询 SELECT message id FROM attachments WHERE l
  • 如何创建 5 个值的数组/切片,所有值都相同

    Problem 在go编程语言中 如何创建一个长度为5的数组 并且所有元素具有相同的值 例如42 优先顺序 可读性 简洁性 性能 例如 package main import fmt func main s make int 5 for i
  • 如何在不输入n的情况下输入数组中的元素? (c++)

    输入 5 long long n cin gt gt n long long a n for long long i 0 i
  • 如何更新/写入数据到谷歌电子表格 api android (api v4)

    我一直在开发一个应用程序 我需要使用谷歌电子表格 API 将数据写入和更新到电子表格 我已经按照google提供的Android Quickstart进行操作谷歌表格API 安卓快速入门 https developers google co
  • window.mozIndexedDB 在 Firefox 15 中为 null

    我正在尝试运行 使用 IndexedDB 示例代码https developer mozilla org en US docs IndexedDB Using IndexedDB https developer mozilla org en
  • 在selenium python中单击滑块按钮

    我的问题如下 我正在接受检索本网站信息的培训https www cetelem es https www cetelem es 我想做几件事 单击两个滑动按钮可更改信息 检索滑动按钮变化后的信息 设置条件 仅在tin和tae改变时检索信息
  • 如何从 PHPMyAdmin 导出 MySQL 数据库并将其导入到 SQLite?

    我想从 PHPMyAdmin 或 MySQl Workbench 导出数据库并将其导入 SQLite 数据库 以便我可以进行本地编辑和测试 而不会搞砸实时版本 我对 SQL 非常陌生 所以此时所有导出选项等对我来说都相当密集 我尝试使用默认
  • SQL查询获取连接航班的src到dest路径

    我想解决一个问题 我希望找到从 src 到dest 的飞行路径 包括转机航班 如果可能的话 按所需时间对其进行排序 我可以使用像 listagg 这样的东西以某种方式将中间航班聚合为字符串吗 我们可以将转机航班的数量和所用的时间限制在一定范