mysql 递归查询未显示所有可能的结果

mysql recursive query not showing all possible results

我正在尝试按照下方 link 中的火车路线示例进行操作

https://www.percona.com/blog/2020/02/13/introduction-to-mysql-8-0-recursive-common-table-expression-part-2/

我的table如下

架构 (MySQL v8.0)

CREATE TABLE `routesy` (
  `id` int(1) DEFAULT NULL,
  `stationA` varchar(6) DEFAULT NULL,
  `stationB` varchar(6) DEFAULT NULL,
  `dist` int(3) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


INSERT INTO `routesy` (`id`, `stationA`, `stationB`, `dist`) VALUES
(1, 'DO0182', 'DO0064', 10),
(2, 'DO0064', 'DO0147', 70),
(3, 'DO0064', 'DO0049', 80),
(4, 'DO0064', 'DO0139', 90),
(5, 'DO0206', 'DO0147', 140),
(6, 'DO0072', 'DO0139', 150),
(7, 'DO0008', 'DO0049', 260),
(8, 'DO0208', 'DO0008', 280);

查询#1

WITH RECURSIVE paths (cur_path, cur_dest, tot_distance) AS (     
          SELECT CAST(stationA AS CHAR(100)), CAST(stationA AS CHAR(100)), 0 
          FROM routesy
          WHERE stationA='DO0182'
          UNION     
          SELECT CONCAT(paths.cur_path, ' -> ', routesy.stationB), routesy.stationB, paths.tot_distance+routesy.dist        
          FROM paths, routesy        
          WHERE paths.cur_dest = routesy.stationA 
           AND  NOT FIND_IN_SET(routesy.stationB, REPLACE(paths.cur_path,' -> ',',') ) ) 
       SELECT cur_path,cur_dest,tot_distance FROM paths;
cur_path cur_dest tot_distance
DO0182 DO0182 0
DO0182 -> DO0064 DO0064 10
DO0182 -> DO0064 -> DO0147 DO0147 80
DO0182 -> DO0064 -> DO0049 DO0049 90
DO0182 -> DO0064 -> DO0139 DO0139 100

View on DB Fiddle

我希望看到下面的结果以及这些是有效路径。为什么递归停在3级?

DO0182 -> DO0064 -> DO0147 -> DO0206
DO0182 -> DO0064 -> DO0139 -> DO0072
DO0182 -> DO0064 -> DO0049 -> DO0008 -> DO0208

根据您在 table 中给定的数据:

INSERT INTO `routesy` (`id`, `stationA`, `stationB`, `dist`) VALUES
(1, 'DO0182', 'DO0064', 10),
(2, 'DO0064', 'DO0147', 70),
(3, 'DO0064', 'DO0049', 80),
(4, 'DO0064', 'DO0139', 90),
(5, 'DO0206', 'DO0147', 140),
(6, 'DO0072', 'DO0139', 150),
(7, 'DO0008', 'DO0049', 260),
(8, 'DO0208', 'DO0008', 280);

和查询“stationA='DO0182'”中的起点,正如查询结果所示,我们只能跟踪 3 个级别。

路径是单向的,即站 A -> 站 B 是路径中唯一考虑的方向(不是站 B -> 站 A)。

希望这对您有所帮助。

根据@vtan707 的回答,使路由双向的方法是添加另一个UNION,例如:

WITH RECURSIVE paths (cur_path, cur_dest, tot_distance) AS (     
          SELECT CAST(stationA AS CHAR(100)), CAST(stationA AS CHAR(100)), 0 
          FROM routesy
          WHERE stationA='DO0182'
          UNION 
          SELECT CONCAT(paths.cur_path, ',', routesy.stationB), routesy.stationB, paths.tot_distance+routesy.dist        
          FROM paths JOIN routesy ON paths.cur_dest = routesy.stationA 
           AND  NOT FIND_IN_SET(routesy.stationB, paths.cur_path) 
          UNION 
          SELECT CONCAT(paths.cur_path, ',', routesy.stationA), routesy.stationA, paths.tot_distance+routesy.dist        
          FROM paths JOIN routesy ON paths.cur_dest = routesy.stationB 
           AND  NOT FIND_IN_SET(routesy.stationA, paths.cur_path)
     ) 
     SELECT REPLACE(cur_path,',',' -> '),cur_dest,tot_distance FROM paths;

因此第二个 UNION 与第一个 stationAstationB 转置相同。

在结果集中替换一次 sytnax 可能也更容易。

参考:mysql-8.0 fiddle

截至 10.5,MariaDB 有 CYCLE RESTRICT

WITH RECURSIVE paths (start, cur_path, cur_dest, tot_distance) AS (     
          SELECT StationA, CAST(stationA AS CHAR(100)), CAST(stationA AS CHAR(100)), 0 
          FROM routesy
          WHERE stationA='DO0182'
          UNION     
          SELECT StationA, CONCAT(paths.cur_path, ' -> ', routesy.stationB), routesy.stationB, paths.tot_distance+routesy.dist        
          FROM paths JOIN routesy ON paths.cur_dest = routesy.stationA 
          UNION     
          SELECT StationB, CONCAT(paths.cur_path, ' -> ', routesy.stationA), routesy.stationA, paths.tot_distance+routesy.dist        
          FROM paths JOIN routesy ON paths.cur_dest = routesy.stationB 
)
CYCLE start, cur_dest RESTRICT
SELECT start, cur_path,cur_dest, tot_distance FROM paths;

ref mariadb-10.5 fiddle

注意:这在旅程结束时有小循环,我还没有解决(因此结果是 17 行而不是 9 行 - 参见 fiddle)。