在SQL Server中实现最短路径搜索的解决方法
在接下来,我就描述在SQL Server中,如何实现。当然我这里采用的前面说的第2种方法,以"P"和"J"为始点像中心外层层扩展。
第1方法是,
use TestDBselect * Into #Path2 from cte_path2
图3.
('o','i'),('o','l')
('a','b'),('a','c'),('a','d'),('a','e'),

复制代码 代码如下:
Not exists(select 1 from #1 where Node=a.Node)where exists(select 1 from #2 where RelatedNode=a.Node And Level=@level) And
)
go
--下面是构造返回的结果路径
return
从上面可以看出第2种可能路径,经过的节点最少。
Node nvarchar(50),--相对源点--
go
select Node, RelatedNode, @level from RelationGraph a where a.Node =@RelatedNode union --正向:以@RelatedNode作为源查询
if @RelatedNode_WhileFlag >0
From #Path1 a
and b.Level=a.Level-1
了能够更好的描述表RelationGraph中字段Node和 RelatedNode的关系,我在这里特意使用一个图形来描述,
From RelationGraph a
union all
('c','i'),('c','j'),
end(
select distinct RelationGraphPath,StopCount From cte_result where Result_row=1
复制代码 代码如下:
解析:
图2.
end如图2.
create table RelactionGraph(ID int identity,Item nvarchar(50),RelactionItem nvarchar(20),constraint PK_RelactionGraph primary key(ID))
;with cte_result Aswhere exists(select 1 from #2 where RelatedNode=a.RelatedNode And Level=@level) And
While_Out:
if not exists(select 1 from #1) or not exists(select 1 from #2)
--如果直接找到两个Node存在直接关系就直接返回
('f','k'),('f','l'),
end
set nocount on
(
And @level<@MaxLevel --控制深度
and b.Level=a.Level-1
在图2,可清晰的看出各个节点直接如何相连,也可以清楚的看出节点"p"至节点"j"的的几种可能路径。
from cte_path1 aselect b.Node,a.RelatedNode,b.Level,convert(nvarchar(2000),b.Node+' -> '+a.RelationGraphPath) As RelationGraphPath ,Convert(smallint,a.PathLevel+1) As PathLevel
goto While_Out
)
Not exists(select 1 from #2 where Node=a.Node)
end

图1.
begin
insert into #2 ( Node, RelatedNode, Level )
inner join #2 b on b.RelatedNode=a.Node
go
select a.Node,a.RelatedNode,Level,convert(nvarchar(2000),a.Node+' -> '+a.RelatedNode) As RelationGraphPath,Convert(smallint,1) As PathLevel From #1 a where exists(select 1 from #2 where RelatedNode=a.RelatedNode)
复制代码 代码如下:

declare
if Exists(select 1 from RelationGraph where (Node=@Node And RelatedNode=@RelatedNode) or (Node=@RelatedNode And RelatedNode=@Node) ) or @Node=@RelatedNode
RelatedNode nvarchar(50), --相对目标
create proc up_GetPath
--反向
这是去年的问题了,今天在整理邮件的时候才发现这个问题,感觉顶有意思的,特记录下来。 @Node_WhileFlag bit=1, --以@Node作为中心进行搜索时候,作为能否循环搜索的标记
set @RelatedNode_WhileFlag=sign(@@rowcount)
('b','f'),('b','g'),('b','h'),
)Drop proc up_GetPath
create nonclustered index IX_RelactionGraph_Item on RelactionGraph(Item) include(RelactionItem)
beginif object_id('tempdb..#2') Is not null Drop Table #2 --临时表#2,存储的是以@RelatedNode作为中心向外扩展的各节点数据
)
if @Node_WhileFlag >0
select b.Node,a.RelatedNode,b.Level,convert(nvarchar(2000),a.RelationGraphPath+' -> '+b.Node) As RelationGraphPath ,Convert(smallint,a.PathLevel+1)
select a.RelatedNode,a.Node,@level+1
select convert(nvarchar(2000),@Node + ' --> '+ @RelatedNode) As RelationGraphPath,convert(smallint,0) As StopCount
while not exists(select 1 from #1 a inner join #2 b on b.RelatedNode=a.RelatedNode) --判断是否出现切点
if object_id('tempdb..#1') Is not null Drop Table #1 --临时表#1,存储的是以@Node作为中心向外扩展的各节点数据
;with cte_path2 As
where a.Level=1
if object_id('tempdb..#Path1') Is not null Drop Table #Path1
inner join #Path2 b on b.RelatedNode=a.RelatedNode
go
where exists(select 1 from #1 where RelatedNode=a.RelatedNode And Level=@level) And
As
From RelationGraph a
end
select * Into #Path1 from cte_path1
if object_id('tempdb..#Path2') Is not null Drop Table #Path2
if object_id('up_GetPath') Is not null
Level smallint --深度
在表RelationGraph中,有三个字段(ID,Node,RelatedNode),其中Node和RelatedNode两个字段描述两个节点的连接关系;现在要求,找出从节点"p"至节点"j",最短路径(即经过的节点最少)。
select RelatedNode, Node, @level from RelationGraph a where a.RelatedNode = @RelatedNode --反向:以@RelatedNode作为目标进行查询
--如果在表RelationGraph中找不到@Node 或 @RelatedNode 数据,就直接跳过后面的While过程
insert into #1 ( Node, RelatedNode, Level )
create nonclustered index IX_RelactionGraph_RelactionItem on RelactionGraph(RelactionItem) include(Item)
开始
为了解决开始的问题,我参考了两种方法,
@RelatedNode_WhileFlag bit=1 --以@RelatedNode作为中心进行搜索时候,作为能否循环搜索的标记select a.RelationGraphPath+' -> '+b.RelationGraphPath As RelationGraphPath,a.PathLevel+b.PathLevel -1 As StopCount,rank() over(order by a.PathLevel+b.PathLevel) As Result_row
下面是存储过程的执行:
select @level+=1
--反向
('k','o'),('k','p'),

inner join #1 b on b.RelatedNode=a.Node
union
Not exists(select 1 from #1 where Node=a.RelatedNode)
begin
第2方法是,
set @RelatedNode_WhileFlag=sign(@@rowcount)insert into RelactionGraph (Item, RelactionItem ) values
use TestDB针对第1种方法的改进,就是采用多源点方法,这里就是以节点"p"和节点"j"为中心向外层扩展,直到两圆外切点,如图4. :
--Procedure:select a.Node,a.RelatedNode,@level+1
@level smallint =1, --当前搜索的深度
union all
select a.Node,a.RelatedNode,@level+1
--正向
@MaxLevel smallint=100, --最大可搜索深度
go
go
go
create table #2(Node nvarchar(50),RelatedNode nvarchar(50),Level smallint)
上面的存储过程,主要分为两大部分,第1部分是实现如何搜索,第2部分实现如何构造返回结果。其中第1部分的代码根据前面的方法2,通过@Node 和 @RelatedNode 两个节点向外层搜索,每次搜索返回的节点都保存至临时表#1和#2,再判断临时表#1和#2有没有出现切点,如果出现就说明已找到最短的路径(经过多节点数最少),否则就继续循环搜索,直到循环至最大的搜索深度(@MaxLevel smallint=100)或找到切点。要是到100层都没搜索到切点,将放弃搜索。这里使用最大可搜索深度@MaxLevel,目的是控制由于数据量大可能会导致性能差,因为在这里数据量与搜索性能成反比。代码中还说到一个正向和反向搜索,主要是相对Node 和 RelatedNode来说,它们两者互为参照对象,进行向外搜索使用。 set @Node_WhileFlag=sign(@@rowcount)
insert into #2 ( Node, RelatedNode, Level )
Not exists(select 1 from #2 where Node=a.RelatedNode)
;with cte_path1 As
编写一个存储过程up_GetPath
实现:
union
where exists(select 1 from #1 where RelatedNode=a.Node And Level=@level) And
图4.
if object_id('RelactionGraph') Is not null drop table RelactionGraph
(From RelationGraph a
参考单源最短路径算法:
)
From RelationGraph a
set @Node_WhileFlag=sign(@@rowcount)

@RelatedNode nvarchar(50)
create table #1(
这里提供有表RelactionGraph的create& Insert数据的脚本:
(
select a.RelatedNode,a.Node,@level+1
and b.Level=1
begin
from cte_path2 a
and (@Node_WhileFlag|@RelatedNode_WhileFlag)>0 --判断是否能搜索
begin
本站内容来源于网络,如有侵权请与我们联系,我们会及时删除,我们深感抱歉!
注:本站所有信息仅供用于网络技术学习参考,学习中请遵循相关法律法规!
本文地址: https://www.juheyunku.com/sql/mssql/3115.shtml
相关文章
热门TAG
命令 权重 外链 企业网站 白帽 php 织梦教程 dedecms修改内容 javascript 织梦 功能 标签 调用 详解 服务器 网站流量 实例解析 Dedecms 织梦cms HTML tags标签 python jquery教程 jquery windows SEO优化 蜘蛛 搜索引擎 网站收录 JSP最新文章
-
sql server 关于设置null的一
时间:2020-12-28
-
详解SQL游标的用法
时间:2020-12-27
-
vs code连接sql server数据库步
时间:2020-12-27
-
图书管理系统的sqlserver数
时间:2020-12-25
-
详解SQL 通配符
时间:2020-12-25
-
sql四大排名函数之ROW_NUM
时间:2020-12-25
-
SQLServer数据库处于恢复挂
时间:2020-12-24
-
Win10 64位安装个人版SQL20
时间:2020-12-24
热门文章
-
sqlserver中查询横表变竖表的sql语句简析
时间:2020-12-08
-
关于SQL Server查询语句的使用
时间:2020-12-13
-
SQL Server简单模式下误删除堆表记录恢复方
时间:2020-12-12
-
MSSQL教程_mssql数据库教程_MSSQL基础教程_第
时间:2020-12-13
-
详解SQL游标的用法
时间:2020-12-27
-
sql server 关于设置null的一些建议
时间:2020-12-28
-
jdbc连接sql server数据库问题分析
时间:2020-12-10
-
mssql关于一个表格结构的另外一种显示(表
时间:2020-12-11
-
SQL Server数据库入门学习总结
时间:2020-12-10
-
使用SqlBulkCopy时应注意Sqlserver表中使用缺
时间:2020-12-09
