公交车路线查询系统后台数据库设计--查询算法

1. 公交车路线信息在数据库中的存储方式

显然,如果在数据库中简单的使用表bus_route(路线名,路线经过的站点,费用)来保存公交车路线的线路信息,则很难使用查询语句实现乘车线路查询,因此,应该对线路的信息进行处理后再保存到数据库中,笔者使用的方法是用站点-路线关系表stop_route(站点,路线名,站点在路线中的位置)来存储公交车路线,例如,如果有以下3条路线

R1: S1->S2->S3->S4->S5

R2: S6->S7->S2->S8

R3: S8->S9->S10

则对应的站点-路线关系表stop_route

Stop

Route

Position

S1

R1

1

S2

R1

2

S3

R1

3

S4

R1

4

S5

R1

5

S6

R2

1

S7

R2

2

S2

R2

3

S8

R2

4

S8

R3

1

S9

R3

2

S10

R3

3

注:Stop为站点名,Route为路线名,Position为站点在路线中的位置

2.直达乘车路线查询算法

基于表stop_route可以很方便实现直达乘车路线的查询,以下是用于查询直达乘车路线的存储过程InquiryT0 

create proc InquiryT0(@StartStop varchar(32),@EndStop varchar(32))
as
begin
    select
        sr1.Stop as 启始站点,
        sr2.Stop as 目的站点,
        sr1.Route as 乘坐线路,
        sr2.Position-sr1.Position as 经过的站点数
    from
        stop_route sr1,
        stop_route sr2
    where
        sr1.Route=sr2.Route
        and sr1.Position<sr2.Position
        and sr1.Stop=@StartStop
        and sr2.Stop=@EndStop
end

3.查询换乘路线算法

(1)直达路线视图

直达路线视图可以理解为一张存储了所有直达路线的表(如果两个站点之间存在直达路线,那么在直达路线视图中就有一行与之相对应)。例如R1,R2,R3对应的RouteT0如下: 

起点

终点

乘坐路线

站点数

S3

S4

R1

1

S3

S5

R1

2

S4

S5

R1

1

S1

S2

R1

1

S1

S3

R1

2

S1

S4

R1

3

S1

S5

R1

4

S2

S3

R1

1

S2

S4

R1

2

S2

S5

R1

3

S2

S8

R2

1

S6

S2

R2

2

S6

S7

R2

1

S6

S8

R2

3

S7

S2

R2

1

S7

S8

R2

2

S8

S10

R3

2

S8

S9

R3

1

S9

S10

R3

1

RouteT0定义如下:

create view RouteT0
as
    select
        sr1.Stop as StartStop,    --启始站点
        sr2.Stop as EndStop,    --目的站点
        sr1.Route as Route,    --乘坐线路
        sr2.Position-sr1.Position as StopCount    --经过的站点数
    from
        stop_route sr1,
        stop_route sr2
    where
        sr1.Route=sr2.Route
        and sr1.Position<sr2.Position 

(2)换乘路线算法

显然,一条换乘路线由若干段直达路线组成(每段路线的终点与下一段路线的起点相同),因此,基于直达路线视图RouteT0可以很方便实现换乘查询,以下是实现一次换乘查询的存储过程InquiryT1 

create proc InquiryT1(@StartStop varchar(32),@EndStop varchar(32))
as
begin
    select
        r1.StartStop as 启始站点,
        r1.Route as 乘坐路线1,
        r1.EndStop as 中转站点,
        r2.Route as 乘坐路线2,
        r2.EndStop as 目的站点,
        r1.StopCount+r2.StopCount as 总站点数
    from
        RouteT0 r1,
        RouteT0 r2
    where
        r1.StartStop=@StartStop
        and r1.EndStop=r2.StartStop
        and r2.EndStop=@EndStop
end

同理可以得到二次换乘的查询语句

create proc InquiryT2(@StartStop varchar(32),@EndStop varchar(32))
as
begin
    select
        r1.StartStop as 启始站点,
        r1.Route as 乘坐路线1,
        r1.EndStop as 中转站点1,
        r2.Route as 乘坐路线2,
        r2.EndStop as 中转站点2,
        r3.Route as 乘坐路线3,
        r3.EndStop as 目的站点,
        r1.StopCount+r2.StopCount+r3.StopCount as 总站点数
    from
        RouteT0 r1,
        RouteT0 r2,
        RouteT0 r3
    where
        r1.StartStop=@StartStop
        and r1.EndStop=r2.StartStop
        and r2.EndStop=r3.StartStop
        and r3.EndStop=@EndStop
end 

4.测试

exec InquiryT0 'S1','S2'
exec InquiryT1 'S1','S8'
exec InquiryT2 'S1','S9'

运行结果:

 

 

作者:卢春城
E-mail:mrlucc@126.com
出处:http://lucc.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
posted @ 2009-02-11 23:27 卢春城 阅读(8985) 评论(21) 编辑 收藏

 回复 引用 查看   
#1楼 2009-02-11 23:32 Microshaoft      
图?
边?
点?

 回复 引用 查看   
#2楼 2009-02-12 07:11 Tony Qu      
很实用的文章,可否再写写站名模糊匹配方面的算法?
因为通常情况下可能出现站名打错或者写的是附近地名的情况

 回复 引用 查看   
#3楼[楼主] 2009-02-12 07:51 卢春城      
@Tony Qu
建立一张站点表保存所有站点,根据用户输入的关键字用like搜索出站点供用户选择

 回复 引用   
#4楼 2009-02-12 08:41 nono[未注册用户]
to 3 楼:
like 模糊查询 在海量数据里 不可取吧


 回复 引用 查看   
#5楼[楼主] 2009-02-12 09:30 卢春城      
@nono
公交车站点一般也就几千个,用like查找还是很快的

1.根据用户输入的起点和终点的关键字从站点表中搜索出相关站点(只有这一步使用了like)
2.由用户选择一个起点和一个终点
3.调用查询路线的存储过程进行查询

 回复 引用   
#6楼 2009-02-12 10:44 abc123[未注册用户]
如果线路调整,比如某条线路增加或减少了一个站的话,那不是要逐一修改数据表?有没更好的方法?
 回复 引用 查看   
#7楼 2009-02-12 11:12 乾元御天      
怎么查最近线路呢?

 回复 引用 查看   
#8楼[楼主] 2009-02-12 11:28 卢春城      
@abc123
以文章中的例子为例,假如R3由 S8->S9->S10变为 S8->S11->S9->S10
1.用delete from stop_route where Route='R3'刪除线路R3
2.重新插入R3

 回复 引用 查看   
#9楼[楼主] 2009-02-12 11:29 卢春城      
@乾元御天
本文的主要目的是查询算法,如果要查最近线路,需要建立其他的表以保存相关信息
如果按照总站点数来判断距离的话,可以按StopCount排序

 回复 引用 查看   
#10楼 2009-02-12 12:38 canbeing      
好是好,感觉效率却是一个问题
 回复 引用 查看   
#11楼[楼主] 2009-02-12 13:05 卢春城      
@canbeing
实际应用时RouteT0可以不用视图而是直接使用表,并且在StartStop和EndStop列上创建索引,提高查询效率
假设有350条公交路线(上行线和下行线分开考虑则有700条),每条路线平均20个站点,那么RouteT0约有30万行

 回复 引用 查看   
#12楼 2009-02-12 13:28 毁于随      
思路挺好的,就是不知道效率是否为最优的.
 回复 引用 查看   
#13楼 2009-02-12 16:29 KindSoul      
想法不错,
可用with as语法逐步筛选,来增加效率。

 回复 引用 查看   
#14楼 2009-03-23 16:20 大头瓜      
测试了一下
exec InquiryT1 '北京路口' ,'爱群大厦'
exec InquiryT2 '北京路口' ,'爱群大厦'
结果第一句为372条记录,第二句为55308条记录
呵呵

写得很好,简单明了
 回复 引用   
#16楼 2009-05-27 11:13 T-T[未注册用户]
exec InquiryT0 'S5','S2'
exec InquiryT1 'S1','S6'
以上两句无查询结果,第一个查询可将将s5和s2互换得查询结果,第二个怎么办呢?

 回复 引用 查看   
#17楼[楼主] 2009-05-27 16:28 卢春城      
@T-T
这些路线都是单向的,现实中可将公交车路线的上下行线当成两条路线

 回复 引用   
#18楼 2009-05-30 01:28 xiaoga[未注册用户]
可否请教一个问题:按照你的算法,在数据库中添加了数据,执行存储过程的时候参数不能是汉字,不然没结果,用字母却可以,是数据库的哪点出了问题,新手,谢谢
 回复 引用 查看   
#19楼[楼主] 2009-05-30 17:07 卢春城      
@xiaoga
试一下使用nvarchar代替varchar

 回复 引用 查看   
#20楼 2010-05-05 20:19 weiwelcome0      
好文章,简单明了
 回复 引用 查看   
#21楼 2011-09-21 16:11 錵✿      
exec InquiryT0 'S2','S1'
exec InquiryT1 'S8','S1'
exec InquiryT2 'S9','S1'
把线路 倒过来 就都查询不到了啊