【问题标题】:Trying to get direct, indirect, intersecting routes for public transport using an sql query尝试使用 sql 查询获取公共交通的直接、间接、相交路线
【发布时间】:2015-11-10 13:49:53
【问题描述】:

我正在尝试构建一个查询,获取从 A 到 B 的路线。有时可能有直接路线,有时我需要找到交叉点并获取交换路线。目标是让一个人从 A 到 B 并给出不同的模式类型和路线。我稍后会添加最短或最佳路线,但现在只是为了获得正确的路线。问题是当我尝试获取相交路线时。不知何故,我觉得应该有一种更简单的方法来完成这项工作。我希望这不是太多的代码。

我认为应该起作用的逻辑是

  1. 找到起始路线(Halts 表),如果我们有一个获取 RouteID 和路线编号,如果找不到起始路线,则尝试获取下一个最近的路线。

  2. 找到终点路线。如果有,请检查起始路线是否在此路线内(这是直接路线),如果是,则获取 RouteID 和路线编号并插入临时表以显示最终路线。

    1. 如果点 2 没有终点路线,则尝试从起点查找相交路线,并查找是否有任何相交的路线,如果是,则获取该路线 ID 和路线编号。从相交路线尝试是否可以到达终点路线this is where I got lost as there can be more than one intersecting route

RouteTypes 表

此表有不同的路线类型,如城市巴士、长途巴士、本地火车、长途火车、国内航班、国际航班

    CREATE TABLE [dbo].[RouteTypes](
    [RouteTypeID] [int] IDENTITY(1,1) NOT NULL,
    [ModeTypeID] [int] NOT NULL,
    [RouteType] [nvarchar](50) NOT NULL,
 CONSTRAINT [PK_RouteTypes] PRIMARY KEY CLUSTERED 
(
    [RouteTypeID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

模式类型表

此表将包含不同的交通类型,如公共汽车、火车、航班

CREATE TABLE [dbo].[ModeTypes](
    [ModeTypeID] [int] IDENTITY(1,1) NOT NULL,
    [ModeType] [nvarchar](50) NOT NULL,
    [IsEnabled] [bit] NOT NULL,
 CONSTRAINT [PK_ModeTypes] PRIMARY KEY CLUSTERED 
(
    [ModeTypeID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

暂停表格

此表将保存所有暂停,并且是暂停的主表

CREATE TABLE [dbo].[Halts](
    [HaltID] [int] IDENTITY(1,1) NOT NULL,
    [Halt] [nvarchar](100) NOT NULL
) ON [PRIMARY]

路线表

这个表会有一些路线编号。由于我不太清楚需要在此处添加什么,因此我目前未使用的大多数字段

CREATE TABLE [dbo].[Routes](
    [RouteID] [int] IDENTITY(1,1) NOT NULL,
    [RouteTypeID] [int] NOT NULL,
    [RouteNo] [nvarchar](30) NOT NULL,
    [Duration] [nvarchar](30) NULL,
    [Distance] [nvarchar](30) NULL,
    [OldRouteNo] [nvarchar](30) NULL,
    [DaysAvailable] [char](15) NULL,
    [IsEnabled] [bit] NOT NULL,
    [BeginAt] [time](7) NULL,
    [EndAt] [time](7) NULL,
 CONSTRAINT [PK_Routes] PRIMARY KEY CLUSTERED 
(
    [RouteID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

路由暂停表

CREATE TABLE [dbo].[RouteHalts](
    [RouteHaltID] [int] IDENTITY(1,1) NOT NULL,
    [RouteID] [int] NOT NULL,
    [FirstLastHalt] [char](1) NULL,
    [HaltNo] [smallint] NULL,
    [HaltID] [int] NOT NULL,
 CONSTRAINT [PK_RouteHalts] PRIMARY KEY CLUSTERED 
(
    [RouteHaltID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

我正在使用存储过程,这就是我到目前为止所得到的。当我得到检查路线时,结果有些不正确。

DECLARE @StartingRouteID int;
    DECLARE @EndingRouteID int;
    DECLARE @CrossRouteHalt  nvarchar(100);

    CREATE TABLE #TmpStartingRoute  
            (  
            ID INT IDENTITY(1,1) NOT NULL,
            RouteID int null,
            RouteNo nvarchar(60) null,
            RouteType nvarchar(100) null,
            Duration nvarchar(60) null,
            Distance nvarchar(60) null,
            DaysAvailable nvarchar(60) null,
            Halt nvarchar(100) null,
            ModeType nvarchar(100) null
            )

      CREATE TABLE #TmpStartingHalts  
            (  
            ID INT IDENTITY(1,1) NOT NULL,
            RouteID int null,     
            RouteNo nvarchar(60) null,
            RouteType nvarchar(100) null,
            Duration nvarchar(60) null,
            Distance nvarchar(60) null,
            DaysAvailable nvarchar(60) null,
            Halt nvarchar(100) null,
            ModeType nvarchar(100) null
            )


    CREATE TABLE #TmpEndingRoute  
            (  
            ID INT IDENTITY(1,1) NOT NULL,
            RouteID int null,
            RouteNo nvarchar(60) null,
            RouteType nvarchar(100) null,
            Duration nvarchar(60) null,
            Distance nvarchar(60) null,
            DaysAvailable nvarchar(60) null,
            Halt nvarchar(100) null,
            ModeType nvarchar(100) null
            )

             CREATE TABLE #TmpEndingHalts  
            (  
            ID INT IDENTITY(1,1) NOT NULL,
            RouteID int null,
            RouteNo nvarchar(60) null,
            RouteType nvarchar(100) null,
            Duration nvarchar(60) null,
            Distance nvarchar(60) null,
            DaysAvailable nvarchar(60) null,
            Halt nvarchar(100) null,
            ModeType nvarchar(100) null
            )


    CREATE TABLE #TmpRts  
            (  
            ID INT IDENTITY(1,1) NOT NULL,
            RouteID int null,
            Halt nvarchar(100) null,
            RouteNo nvarchar(60) null,
            RouteType nvarchar(100) null,
            ModeType nvarchar(100) null
            )

     CREATE TABLE #TmpIntersection  
            (  
            ID INT IDENTITY(1,1) NOT NULL,
            RouteID int null,
            Halt nvarchar(100) null,
            RouteNo nvarchar(60) null,
            RouteType nvarchar(100) null,
            ModeType nvarchar(100) null
            )

    CREATE TABLE #FinalRoute  
            (  
            ID INT IDENTITY(1,1) NOT NULL,
            RouteID int null,
            RouteNo nvarchar(60) null,
            Halt nvarchar(100) null,
            RouteType nvarchar(100) null,
            ModeType nvarchar(100) null

            )


    -- Check if Starting point exits
    IF EXISTS(SELECT 1 FROM RouteHalts where Halt like'%'+ @StartingPoint +'%') 
        BEGIN
            SELECT 
                @StartingRouteID=R.RouteID
            from 
                ModeTypes M
            inner join 
                RouteTypes RT on M.ModeTypeID=RT.ModeTypeID
            inner join 
                Routes R on RT.RouteTypeID=R.RouteTypeID
            inner join 
                RouteHalts RH on R.RouteID=RH.RouteID
            where 
                RH.Halt like'%'+ @StartingPoint +'%'

            insert into #TmpStartingRoute(RouteID,RouteNo,RouteType,Duration,Distance,DaysAvailable,Halt,ModeType)
                SELECT 
                    R.RouteID, R.RouteNo,RT.RouteType,R.Duration,R.Distance,R.DaysAvailable, RH.Halt,M.ModeType
                from 
              ModeTypes M
                inner join 
                    RouteTypes RT on M.ModeTypeID=RT.ModeTypeID
                inner join 
                    Routes R on RT.RouteTypeID=R.RouteTypeID
                inner join 
                    RouteHalts RH on R.RouteID=RH.RouteID
                where 
                    RH.Halt like'%'+ @StartingPoint +'%'
                order by 
                    R.RouteNo,RH.HaltNo

             -- Insert halts of starting routes
             insert into #TmpStartingHalts(RouteID,RouteNo,RouteType,Duration,Distance,DaysAvailable,Halt,ModeType)
                SELECT 
                    R.RouteID, R.RouteNo,RT.RouteType,R.Duration,R.Distance,R.DaysAvailable, RH.Halt,M.ModeType 
                from 
                    ModeTypes M
                inner join 
                    RouteTypes RT on M.ModeTypeID=RT.ModeTypeID
                inner join 
                    Routes R on RT.RouteTypeID=R.RouteTypeID
                inner join 
                    RouteHalts RH on R.RouteID=RH.RouteID
                where 
                    RH.RouteID=@StartingRouteID and  RH.Halt not like'%'+ @StartingPoint +'%'
                order by 
                    R.RouteNo,RH.HaltNo


        END

    ELSE

        -- Find the closest locaton of the starting point
        BEGIN
            RAISERROR('No Routes Available', 16, 2)
            RETURN
        END

    -- Check if Ending point exits within the start route to get the direct route
    IF EXISTS(SELECT 1 FROM RouteHalts R INNER JOIN #TmpStartingRoute SR on R.RouteID=SR.RouteID
            where R.Halt like'%'+ @EndingPoint +'%') 
        BEGIN
           print 'In End route exists within starting route'

            SELECT 
                @EndingRouteID= R.RouteID
            from 
                ModeTypes M
            inner join 
                RouteTypes RT on M.ModeTypeID=RT.ModeTypeID
            inner join 
                Routes R on RT.RouteTypeID=R.RouteTypeID
            inner join 
                RouteHalts RH on R.RouteID=RH.RouteID
            INNER JOIN
                #TmpStartingRoute SR on R.RouteID=SR.RouteID
            where 
                RH.Halt like'%'+ @EndingPoint +'%'
             insert into #TmpEndingRoute(RouteID,RouteNo,RouteType,Duration,Distance,DaysAvailable,Halt,ModeType)
            SELECT 
                R.RouteID,R.RouteNo, RT.RouteType,R.Duration,R.Distance,R.DaysAvailable, RH.Halt,M.ModeType 
            from 
                ModeTypes M
            inner join 
                RouteTypes RT on M.ModeTypeID=RT.ModeTypeID
            inner join 
                Routes R on RT.RouteTypeID=R.RouteTypeID
            inner join 
                RouteHalts RH on R.RouteID=RH.RouteID
            INNER JOIN
                #TmpStartingRoute SR on R.RouteID=SR.RouteID
            where 
                RH.Halt like'%'+ @EndingPoint +'%'
            order by 
                R.RouteNo,RH.HaltNo

            -- Insert all halts of ending route 
             insert into #TmpEndingHalts(RouteID,RouteNo,RouteType,Duration,Distance,DaysAvailable,Halt,ModeType)
            SELECT 
                R.RouteID,R.RouteNo, RT.RouteType,R.Duration,R.Distance,R.DaysAvailable, RH.Halt,M.ModeType 
            from 
                ModeTypes M
            inner join 
                RouteTypes RT on M.ModeTypeID=RT.ModeTypeID
            inner join 
                Routes R on RT.RouteTypeID=R.RouteTypeID
            inner join 
                RouteHalts RH on R.RouteID=RH.RouteID
            where 
               RH.RouteID=@EndingRouteID and RH.Halt not like'%'+ @EndingPoint +'%'
            order by 
                R.RouteNo,RH.HaltNo


        delete from #TmpStartingHalts where RouteID not in (select RouteID from #TmpEndingRoute)
        delete from #TmpStartingRoute where RouteID not in (select RouteID from #TmpEndingRoute)
        select * from #TmpEndingRoute
        END


    ELSE

        -- Find the closest locaton of the starting point
        BEGIN
            print 'In End route does NOT exists within starting route'
           SELECT 
                @EndingRouteID= R.RouteID
            from 
                ModeTypes M
            inner join 
                RouteTypes RT on M.ModeTypeID=RT.ModeTypeID
            inner join 
                Routes R on RT.RouteTypeID=R.RouteTypeID
            inner join 
                RouteHalts RH on R.RouteID=RH.RouteID

            where 
                RH.Halt like'%'+ @EndingPoint +'%'
             insert into #TmpEndingRoute(RouteID,RouteNo,RouteType,Duration,Distance,DaysAvailable,Halt,ModeType)
            SELECT 
                R.RouteID,R.RouteNo, RT.RouteType,R.Duration,R.Distance,R.DaysAvailable, RH.Halt,M.ModeType 
            from 
                ModeTypes M
            inner join 
                RouteTypes RT on M.ModeTypeID=RT.ModeTypeID
            inner join 
                Routes R on RT.RouteTypeID=R.RouteTypeID
            inner join 
                RouteHalts RH on R.RouteID=RH.RouteID

            where 
                RH.Halt like'%'+ @EndingPoint +'%'
            order by 
                R.RouteNo,RH.HaltNo

            -- Insert all halts of ending route 
             insert into #TmpEndingHalts(RouteID,RouteNo,RouteType,Duration,Distance,DaysAvailable,Halt,ModeType)
            SELECT 
                R.RouteID,R.RouteNo, RT.RouteType,R.Duration,R.Distance,R.DaysAvailable, RH.Halt,M.ModeType 
            from 
                ModeTypes M
            inner join 
                RouteTypes RT on M.ModeTypeID=RT.ModeTypeID
            inner join 
                Routes R on RT.RouteTypeID=R.RouteTypeID
            inner join 
                RouteHalts RH on R.RouteID=RH.RouteID
            where 
               RH.RouteID=@EndingRouteID and RH.Halt not like'%'+ @EndingPoint +'%'
            order by 
                R.RouteNo,RH.HaltNo
        END

    -- Get the intersection Routes
        insert into #TmpRts(RouteID,Halt,RouteNo,RouteType,ModeType)
       select RH.RouteID,RH.halt,TER.RouteNo,TER.RouteType,TER.ModeType
        from 
            RouteHalts RH
        INNER JOIN 
            #TmpEndingRoute TER on RH.RouteID=TER.RouteID 

    -- Get the intersection Halt
    IF EXISTS( select 1 from RouteHalts RH INNER JOIN #TmpRts TER on TER.Halt=RH.Halt
            where RH.RouteID in (select RouteID from #TmpStartingRoute))
            begin
            print 'in exists'
        select 
            @CrossRouteHalt= TER.Halt 
        from 
            RouteHalts RH
        INNER JOIN 
            #TmpRts TER on TER.Halt=RH.Halt
        where RH.RouteID in (select RouteID from #TmpStartingRoute)

        -- Insert into #TmpIntersection 
        insert into #TmpIntersection(RouteID,Halt,RouteNo,RouteType,ModeType)
        select RH.RouteID,RH.Halt,RouteNo,RouteType,ModeType 
        from 
            RouteHalts RH
        INNER JOIN 
            #TmpRts TER on TER.Halt=RH.Halt
            where RH.RouteID in (select RouteID from #TmpStartingRoute)
        end
   -- If no intersection halt exsits then try to get the matching routes from the starting point halts
    IF not EXISTS( select 1 from RouteHalts RH INNER JOIN #TmpRts TER on TER.Halt=RH.Halt
            where RH.RouteID in (select RouteID from #TmpStartingRoute))
        begin
            print 'in not exists'

            insert into #TmpRts(RouteID,Halt,RouteNo)
            select distinct RH.RouteID,RH.halt,TSR.RouteNo
            from
                RouteHalts RH
            INNER JOIN 
                #TmpStartingHalts TSR on RH.Halt=TSR.Halt

            -- Update the Route type to show the current route type of the connecting routes
            update TER
            set TER.RouteType =  RT.RouteType, TER.ModeType=MT.ModeType
                from  #TmpRts TER
            INNER JOIN Routes R on TER.RouteID=R.RouteID
            inner join 
                RouteTypes RT on R.RouteTypeID=RT.RouteTypeID
            inner join 
                ModeTypes MT on RT.ModeTypeID=MT.ModeTypeID

            select 
                @CrossRouteHalt= TSR.Halt 
            from 
                RouteHalts RH
            INNER JOIN 
                #TmpRts TSR on TSR.Halt=RH.Halt
            where RH.RouteID in (select RouteID from #TmpStartingHalts)

            -- Insert into #TmpIntersection 
        insert into #TmpIntersection(RouteID,Halt,RouteNo,RouteType,ModeType)
        select RH.RouteID,RH.Halt,RouteNo,RouteType,ModeType 
        from 
            RouteHalts RH
        INNER JOIN 
            #TmpRts TSR on TSR.Halt=RH.Halt
            where RH.RouteID in (select RouteID from #TmpStartingHalts)
        end



    /*
        Insert all data in to #FinalRoute
    */

    -- Insert the Starting Route record
    insert into #FinalRoute(RouteID,Halt,RouteNo,RouteType,ModeType)
    select RouteID,Halt,RouteNo,RouteType,ModeType from #TmpStartingRoute

    -- Insert the Intersection Halt
    insert into #FinalRoute(Halt)
    select @CrossRouteHalt

    -- Get the new Starting point 
    delete from #TmpRts where routeid in (select routeid from #TmpStartingRoute)
    select RH.RouteID,RH.halt,R.RouteNo,TER.RouteType,TER.ModeType
    into #TmpNewStartingPoint
        from 
            RouteHalts RH
        INNER JOIN 
            #TmpRts TER on RH.RouteID=TER.RouteID and TER.RouteID not in (select routeid from #TmpEndingRoute)
        inner join Routes R on TER.RouteID=R.RouteID and TER.RouteID not in (select routeid from #TmpEndingRoute)


    /*
        Insert all data in to #FinalRoute
    */


    -- Check if #TmpNewStartingPoint is empty then add the insersection route from #TmpRts else add the data from #TmpNewStartingPoint
    IF NOT EXISTS(select 1 from #TmpNewStartingPoint) 
    BEGIN
        print 'in no new starting point'
        insert into #FinalRoute(RouteID,Halt,RouteNo,RouteType,ModeType)
        select RouteID, Halt,RouteNo,RouteType,ModeType from  #TmpRts where Halt=@CrossRouteHalt 

    END

    IF EXISTS(select 1 from #TmpNewStartingPoint) 

    BEGIN
        print 'in new starting point'
        insert into #FinalRoute(RouteID,Halt,RouteNo,RouteType,ModeType)
        select RouteID,Halt,RouteNo,RouteType,ModeType from #TmpNewStartingPoint where halt in (select halt from #TmpEndingHalts)

    END

    -- Insert the Ending Route record
    insert into #FinalRoute(RouteID,Halt,RouteNo,RouteType,ModeType)
    select RouteID,Halt,RouteNo,RouteType,ModeType from #TmpEndingRoute

    select * from #FinalRoute

编辑 1 我发现这些链接很有趣,所以在这里添加它

This link is something similar to what I am trying to do

【问题讨论】:

  • 这是一个巨大的问题,我们在这里的答案中只能触及表面;因此我的投票“过于广泛”。
  • @AakashM 我还在寻找是否有更简单的方法

标签: sql sql-server database


【解决方案1】:

您需要创建一个包含旅行成本的网络网格,以便使用Travel Salesman Promblem 算法(如djistrashort A*)解决旅行问题

就我而言,我使用 postgres lib PgRouting http://workshop.pgrouting.org/chapters/shortest_path.html#

在图中

  • 红色平均地铁路线
  • 绿色平均高速公路路线
  • 绿点表示起点a
  • 蓝点表示终点
  • 黄点表示火车站。通常结束/开始于道路链接,以便您进行路线转换。

链接

  • 道路的速度将达到 60-80 公里/小时
  • 道路也有 3kmh 的步行速度
  • 以 60 公里/小时的恒定速度训练

这样您就可以使用 TSP 算法来优化成本。您使用每个速度指定成本以计算 Time = Distance / Speed 或仅计算 distance。您也可以在使用忽略公交路线等算法之前更改select 中的网格。或使用实时交通改变道路速度

【讨论】:

  • 现在看起来很混乱。但会尝试并在此处添加更新
  • 我接受了这个答案,因为我知道如何继续 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-25
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多