mysql 递归查询未显示所有可能的结果
mysql recursive query not showing all possible results
我正在尝试按照下方 link 中的火车路线示例进行操作
我的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
我希望看到下面的结果以及这些是有效路径。为什么递归停在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
与第一个 stationA
和 stationB
转置相同。
在结果集中替换一次 sytnax 可能也更容易。
截至 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;
注意:这在旅程结束时有小循环,我还没有解决(因此结果是 17 行而不是 9 行 - 参见 fiddle)。
我正在尝试按照下方 link 中的火车路线示例进行操作
我的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 |
我希望看到下面的结果以及这些是有效路径。为什么递归停在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
与第一个 stationA
和 stationB
转置相同。
在结果集中替换一次 sytnax 可能也更容易。
截至 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;
注意:这在旅程结束时有小循环,我还没有解决(因此结果是 17 行而不是 9 行 - 参见 fiddle)。