公用表达式递归求最短路径详解

需求:求从A出发到D的最短路径,如图:
这里写图片描述
WITH T AS(
SELECT ‘A’ S,’B’ E,20 DIST FROM DUAL UNION
SELECT ‘A’ S,’C’ E,10 DIST FROM DUAL UNION
SELECT ‘B’ S,’C’ E,40 DIST FROM DUAL UNION
SELECT ‘B’ S,’D’ E,10 DIST FROM DUAL UNION
SELECT ‘C’ S,’D’ E,30 DIST FROM DUAL
)
SELECT S 起点,E 终点,DIST 距离 FROM T;

STEP1:设置起始点
SELECT ‘A’,’A’,0 FROM DUAL;–即A到A的距离为0

STEP2:STEP1 join T
WITH T AS(
SELECT ‘A’ S,’B’ E,20 DIST FROM DUAL UNION
SELECT ‘A’ S,’C’ E,10 DIST FROM DUAL UNION
SELECT ‘B’ S,’C’ E,40 DIST FROM DUAL UNION
SELECT ‘B’ S,’D’ E,10 DIST FROM DUAL UNION
SELECT ‘C’ S,’D’ E,30 DIST FROM DUAL
),
TMP (P_S,P_E,DIST) AS (SELECT ‘A’ ,’A’ ,0 FROM DUAL)
SELECT T.E P_S,TMP.P_E||’-‘||T.E P_E,TMP.DIST+T.DIST DIST FROM T
JOIN TMP
ON TMP.P_S=T.S;
这里写图片描述
从A出发,下一站有B、C两种可能,
A到B,下一站的起点是B,
A到C,下一站的起点是C

STEP3:STEP2 join T
WITH T AS(
SELECT ‘A’ S,’B’ E,20 DIST FROM DUAL UNION
SELECT ‘A’ S,’C’ E,10 DIST FROM DUAL UNION
SELECT ‘B’ S,’C’ E,40 DIST FROM DUAL UNION
SELECT ‘B’ S,’D’ E,10 DIST FROM DUAL UNION
SELECT ‘C’ S,’D’ E,30 DIST FROM DUAL
),
TMP (P_S,P_E,DIST) AS (
SELECT ‘B’ ,’A-B’ ,20 FROM DUAL UNION ALL
SELECT ‘C’ ,’A-C’ ,10 FROM DUAL
)
SELECT T.E P_S,TMP.P_E||’-‘||T.E P_E,TMP.DIST+T.DIST DIST FROM T
JOIN TMP
ON TMP.P_S=T.S;
这里写图片描述
从B出发,下一站有C、D两种可能
从C出发,下一站有D一种可能

STEP4:STEP3 join T
WITH T AS(
SELECT ‘A’ S,’B’ E,20 DIST FROM DUAL UNION
SELECT ‘A’ S,’C’ E,10 DIST FROM DUAL UNION
SELECT ‘B’ S,’C’ E,40 DIST FROM DUAL UNION
SELECT ‘B’ S,’D’ E,10 DIST FROM DUAL UNION
SELECT ‘C’ S,’D’ E,30 DIST FROM DUAL
),
TMP (P_S,P_E,DIST) AS (
SELECT ‘C’ ,’A-B-C’ ,20 FROM DUAL UNION ALL
SELECT ‘D’ ,’A-B-D’ ,20 FROM DUAL UNION ALL
SELECT ‘D’ ,’A-C-D’ ,10 FROM DUAL
)
SELECT T.E P_S,TMP.P_E||’-‘||T.E P_E,TMP.DIST+T.DIST DIST FROM T
JOIN TMP
ON TMP.P_S=T.S;
这里写图片描述
从C出发,下一站只有D

综上:
WITH T AS(
SELECT ‘A’ S,’B’ E,20 DIST FROM DUAL UNION
SELECT ‘A’ S,’C’ E,10 DIST FROM DUAL UNION
SELECT ‘B’ S,’C’ E,40 DIST FROM DUAL UNION
SELECT ‘B’ S,’D’ E,10 DIST FROM DUAL UNION
SELECT ‘C’ S,’D’ E,30 DIST FROM DUAL
),
TMP (P_S,P_E,DIST) AS(
SELECT ‘A’,’A’,0 FROM DUAL
UNION ALL
SELECT T.E,TMP.P_E||’-‘||T.E,TMP.DIST+T.DIST FROM T
JOIN TMP
ON TMP.P_S=T.S
)
SELECT P_E,DIST FROM TMP
WHERE p_E LIKE ‘%D’;

这里写图片描述

当然用Oracle的connect by prior能更简单地实现这个需求,但公用表达式可用于DB2、SQL Server等各种不同的数据库,个人比较喜欢这种写法。

By:xsh@live.com QQ:122121221

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值